Skip to main content

gtk4/
widget.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{ControlFlow, WeakRef, translate::*};
4
5use crate::{Widget, ffi, prelude::*};
6
7// rustdoc-stripper-ignore-next
8/// Trait containing manually implemented methods of [`Widget`](crate::Widget).
9pub trait WidgetExtManual: IsA<Widget> + 'static {
10    #[doc(alias = "gtk_widget_add_tick_callback")]
11    fn add_tick_callback<P: Fn(&Self, &gdk::FrameClock) -> ControlFlow + 'static>(
12        &self,
13        callback: P,
14    ) -> TickCallbackId {
15        let callback_data: Box<P> = Box::new(callback);
16
17        unsafe extern "C" fn callback_func<
18            O: IsA<Widget>,
19            P: Fn(&O, &gdk::FrameClock) -> ControlFlow + 'static,
20        >(
21            widget: *mut ffi::GtkWidget,
22            frame_clock: *mut gdk::ffi::GdkFrameClock,
23            user_data: glib::ffi::gpointer,
24        ) -> glib::ffi::gboolean {
25            unsafe {
26                let widget: Borrowed<Widget> = from_glib_borrow(widget);
27                let frame_clock = from_glib_borrow(frame_clock);
28                let callback: &P = &*(user_data as *mut _);
29                let res = (*callback)(widget.unsafe_cast_ref(), &frame_clock);
30                res.into_glib()
31            }
32        }
33        let callback = Some(callback_func::<Self, P> as _);
34
35        unsafe extern "C" fn notify_func<
36            O: IsA<Widget>,
37            P: Fn(&O, &gdk::FrameClock) -> ControlFlow + 'static,
38        >(
39            data: glib::ffi::gpointer,
40        ) {
41            unsafe {
42                let _callback: Box<P> = Box::from_raw(data as *mut _);
43            }
44        }
45        let destroy_call = Some(notify_func::<Self, P> as _);
46
47        let id = unsafe {
48            ffi::gtk_widget_add_tick_callback(
49                self.as_ref().to_glib_none().0,
50                callback,
51                Box::into_raw(callback_data) as *mut _,
52                destroy_call,
53            )
54        };
55        TickCallbackId {
56            id,
57            widget: self.upcast_ref().downgrade(),
58        }
59    }
60}
61
62impl<O: IsA<Widget>> WidgetExtManual for O {}
63
64#[derive(Debug)]
65pub struct TickCallbackId {
66    id: u32,
67    widget: WeakRef<Widget>,
68}
69
70impl PartialEq for TickCallbackId {
71    #[inline]
72    fn eq(&self, other: &Self) -> bool {
73        self.id == other.id
74    }
75}
76
77impl TickCallbackId {
78    #[doc(alias = "gtk_widget_remove_tick_callback")]
79    #[doc(alias = "remove_tick_callback")]
80    pub fn remove(self) {
81        if let Some(widget) = self.widget.upgrade() {
82            unsafe {
83                ffi::gtk_widget_remove_tick_callback(widget.to_glib_none().0, self.id);
84            }
85        }
86    }
87}