1use crate::prelude::*;
2use crate::window::Window;
3use fltk_sys::fl;
4use std::{mem, os::raw, panic, ptr};
5
6pub type WidgetPtr = *mut fltk_sys::widget::Fl_Widget;
8
9pub fn grab() -> Option<impl WindowExt> {
11    unsafe {
12        let ptr = fl::Fl_grab();
13        if ptr.is_null() {
14            None
15        } else {
16            Some(crate::window::Window::from_widget_ptr(ptr as *mut _))
17        }
18    }
19}
20
21pub fn set_grab<W: WindowExt>(win: Option<W>) {
23    unsafe {
24        win.map_or_else(
25            || fl::Fl_set_grab(ptr::null_mut()),
26            |w| fl::Fl_set_grab(w.as_widget_ptr() as *mut _),
27        );
28    }
29}
30
31pub fn set_callback<F, W>(widget: &mut W, cb: F)
33where
34    F: FnMut(&mut dyn WidgetExt),
35    W: WidgetExt,
36{
37    unsafe {
38        unsafe extern "C" fn shim(wid: *mut fltk_sys::widget::Fl_Widget, data: *mut raw::c_void) {
39            unsafe {
40                #[allow(clippy::type_complexity)]
41                let a: *mut Box<dyn FnMut(&mut dyn WidgetExt)> =
42                    data as *mut Box<dyn FnMut(&mut dyn WidgetExt)>;
43                let f: &mut (dyn FnMut(&mut dyn WidgetExt)) = &mut **a;
44                let mut wid = crate::widget::Widget::from_widget_ptr(wid);
45                let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&mut wid)));
46            }
47        }
48        let mut _old_data = None;
49        if widget.is_derived() {
50            _old_data = widget.user_data();
51        }
52        #[allow(clippy::type_complexity)]
53        let a: *mut Box<dyn FnMut(&mut dyn WidgetExt)> = Box::into_raw(Box::new(Box::new(cb)));
54        let data: *mut raw::c_void = a as *mut raw::c_void;
55        let callback: fltk_sys::widget::Fl_Callback = Some(shim);
56        fltk_sys::widget::Fl_Widget_set_callback(widget.as_widget_ptr(), callback, data);
57    }
58}
59
60pub unsafe fn set_raw_callback<W>(
87    widget: &mut W,
88    data: *mut raw::c_void,
89    cb: Option<fn(WidgetPtr, *mut raw::c_void)>,
90) where
91    W: WidgetExt,
92{
93    unsafe {
94        let cb: Option<unsafe extern "C" fn(WidgetPtr, *mut raw::c_void)> = mem::transmute(cb);
95        fltk_sys::widget::Fl_Widget_set_callback(widget.as_widget_ptr(), cb, data);
96    }
97}
98
99pub fn first_window() -> Option<impl WindowExt> {
101    unsafe {
102        let x = fl::Fl_first_window();
103        if x.is_null() {
104            None
105        } else {
106            let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
107            Some(x)
108        }
109    }
110}
111
112pub fn next_window<W: WindowExt>(w: &W) -> Option<impl WindowExt> {
114    unsafe {
115        let x = fl::Fl_next_window(w.as_widget_ptr() as *const raw::c_void);
116        if x.is_null() {
117            None
118        } else {
119            let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
120            Some(x)
121        }
122    }
123}
124
125pub fn modal() -> Option<impl WindowExt> {
127    unsafe {
128        let x = fl::Fl_modal();
129        if x.is_null() {
130            None
131        } else {
132            let x = Window::from_widget_ptr(x as *mut fltk_sys::widget::Fl_Widget);
133            Some(x)
134        }
135    }
136}
137
138pub fn delete_widget<Wid: WidgetBase>(wid: Wid) {
140    WidgetBase::delete(wid);
141}
142
143pub fn set_damage(flag: bool) {
145    let flag = if flag { 0x80 } else { 0 };
146    unsafe { fl::Fl_set_damage(flag) }
147}
148
149pub fn damage() -> bool {
151    unsafe { fl::Fl_damage() != 0 }
152}
153
154pub fn pushed() -> Option<impl WidgetExt> {
156    unsafe {
157        let ptr = fl::Fl_pushed();
158        if ptr.is_null() {
159            None
160        } else {
161            Some(crate::widget::Widget::from_widget_ptr(ptr as *mut _))
162        }
163    }
164}
165
166pub fn focus() -> Option<impl WidgetExt> {
168    unsafe {
169        let ptr = fl::Fl_focus();
170        if ptr.is_null() {
171            None
172        } else {
173            Some(crate::widget::Widget::from_widget_ptr(
174                ptr as *mut fltk_sys::widget::Fl_Widget,
175            ))
176        }
177    }
178}
179
180pub fn set_focus<W: WidgetExt>(wid: &W) {
182    unsafe { fl::Fl_set_focus(wid.as_widget_ptr() as *mut raw::c_void) }
183}
184
185pub fn windows() -> Option<Vec<impl WindowExt>> {
187    let mut v: Vec<Window> = vec![];
188    if let Some(first) = first_window() {
189        let first: Window = unsafe { first.as_widget() };
190        v.push(first.clone());
191        let mut win = first;
192        while let Some(wind) = next_window(&win.clone()) {
193            let w = unsafe { wind.as_widget::<Window>() };
194            v.push(w.clone());
195            win = w;
196        }
197        Some(v)
198    } else {
199        None
200    }
201}