1use std::{marker::PhantomData, ops::Deref};
2
3cfg_if::cfg_if! {
4 if #[cfg(windows)] {
5 #[derive(Clone)]
7 #[non_exhaustive]
8 pub enum RawWidget {
9 #[cfg(feature = "win32")]
11 Win32(windows_sys::Win32::Foundation::HWND),
12 #[cfg(feature = "winui")]
14 WinUI(winui3::Microsoft::UI::Xaml::FrameworkElement),
15 }
16 } else if #[cfg(target_os = "macos")] {
17 pub type RawWidget = objc2::rc::Retained<objc2_app_kit::NSView>;
21 } else {
22 #[derive(Clone)]
24 #[non_exhaustive]
25 pub enum RawWidget {
26 #[cfg(all(not(any(windows, target_os = "macos")), feature = "qt"))]
28 Qt(*mut core::ffi::c_void),
29 #[cfg(all(not(any(windows, target_os = "macos")), feature = "gtk"))]
33 Gtk(gtk4::Widget),
34 }
35 }
36}
37
38#[allow(unreachable_patterns)]
39#[cfg(windows)]
40impl RawWidget {
41 #[cfg(feature = "win32")]
43 pub fn as_win32(&self) -> windows_sys::Win32::Foundation::HWND {
44 match self {
45 Self::Win32(hwnd) => *hwnd,
46 _ => panic!("unsupported handle type"),
47 }
48 }
49
50 #[cfg(feature = "winui")]
52 pub fn as_winui(&self) -> &winui3::Microsoft::UI::Xaml::FrameworkElement {
53 match self {
54 Self::WinUI(e) => e,
55 _ => panic!("unsupported handle type"),
56 }
57 }
58}
59
60#[allow(unreachable_patterns)]
61#[cfg(not(any(windows, target_os = "macos")))]
62impl RawWidget {
63 #[cfg(feature = "qt")]
65 pub fn as_qt<T>(&self) -> *mut T {
66 match self {
67 Self::Qt(w) => (*w).cast(),
68 _ => panic!("unsupported handle type"),
69 }
70 }
71
72 #[cfg(feature = "gtk")]
74 pub fn to_gtk(&self) -> gtk4::Widget {
75 match self {
76 Self::Gtk(w) => w.clone(),
77 _ => panic!("unsupported handle type"),
78 }
79 }
80}
81
82#[derive(Clone)]
84pub struct BorrowedWidget<'a> {
85 handle: RawWidget,
86 _p: PhantomData<&'a ()>,
87}
88
89impl BorrowedWidget<'_> {
90 pub unsafe fn borrow_raw(handle: RawWidget) -> Self {
95 Self {
96 handle,
97 _p: PhantomData,
98 }
99 }
100}
101
102impl Deref for BorrowedWidget<'_> {
103 type Target = RawWidget;
104
105 fn deref(&self) -> &Self::Target {
106 &self.handle
107 }
108}
109
110pub trait AsRawWidget {
112 fn as_raw_widget(&self) -> RawWidget;
114}
115
116impl AsRawWidget for RawWidget {
117 #[allow(clippy::clone_on_copy)]
118 fn as_raw_widget(&self) -> RawWidget {
119 self.clone()
120 }
121}
122
123impl AsRawWidget for BorrowedWidget<'_> {
124 #[allow(clippy::clone_on_copy)]
125 fn as_raw_widget(&self) -> RawWidget {
126 self.handle.clone()
127 }
128}
129
130impl<T: AsRawWidget> AsRawWidget for &'_ T {
131 fn as_raw_widget(&self) -> RawWidget {
132 (**self).as_raw_widget()
133 }
134}
135
136pub trait AsWidget {
138 fn as_widget(&self) -> BorrowedWidget<'_>;
140}
141
142impl AsWidget for BorrowedWidget<'_> {
143 fn as_widget(&self) -> BorrowedWidget<'_> {
144 self.clone()
145 }
146}
147
148impl<T: AsWidget + ?Sized> AsWidget for &T {
149 #[inline]
150 fn as_widget(&self) -> BorrowedWidget<'_> {
151 T::as_widget(self)
152 }
153}
154
155impl<'a, T: AsWidget + ?Sized> From<&'a T> for BorrowedWidget<'a> {
156 fn from(value: &'a T) -> Self {
157 value.as_widget()
158 }
159}
160
161#[doc(hidden)]
162#[macro_export]
163macro_rules! impl_as_widget {
164 ($t:ty, $inner:ident) => {
165 impl $crate::AsRawWidget for $t {
166 fn as_raw_widget(&self) -> $crate::RawWidget {
167 self.$inner.as_raw_widget()
168 }
169 }
170 impl $crate::AsWidget for $t {
171 fn as_widget(&self) -> $crate::BorrowedWidget<'_> {
172 unsafe {
173 $crate::BorrowedWidget::borrow_raw($crate::AsRawWidget::as_raw_widget(self))
174 }
175 }
176 }
177 };
178}