winio_handle/
widget.rs

1use std::{marker::PhantomData, ops::Deref};
2
3cfg_if::cfg_if! {
4    if #[cfg(windows)] {
5        /// Raw window handle.
6        #[derive(Clone)]
7        #[non_exhaustive]
8        pub enum RawWidget {
9            /// Win32 `HWND`.
10            #[cfg(feature = "win32")]
11            Win32(windows_sys::Win32::Foundation::HWND),
12            /// WinUI `FrameworkElement`.
13            #[cfg(feature = "winui")]
14            WinUI(winui3::Microsoft::UI::Xaml::FrameworkElement),
15        }
16    } else if #[cfg(target_os = "macos")] {
17        /// [`NSView`].
18        ///
19        /// [`NSView`]: objc2_app_kit::NSView
20        pub type RawWidget = objc2::rc::Retained<objc2_app_kit::NSView>;
21    } else {
22        /// Raw window handle.
23        #[derive(Clone)]
24        #[non_exhaustive]
25        pub enum RawWidget {
26            /// Pointer to `QWidget`.
27            #[cfg(all(not(any(windows, target_os = "macos")), feature = "qt"))]
28            Qt(*mut core::ffi::c_void),
29            /// GTK [`Widget`].
30            ///
31            /// [`Widget`]: gtk4::Widget
32            #[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    /// Get Win32 `HWND`.
42    #[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    /// Get WinUI `FrameworkElement`.
51    #[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    /// Get Qt `QWidget`.
64    #[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    /// Get Gtk `Widget`.
73    #[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/// A borrowed window handle.
83#[derive(Clone)]
84pub struct BorrowedWidget<'a> {
85    handle: RawWidget,
86    _p: PhantomData<&'a ()>,
87}
88
89impl BorrowedWidget<'_> {
90    /// # Safety
91    ///
92    /// The window must remain valid for the duration of the returned
93    /// [`BorrowedWidget`].
94    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
110/// Trait to exact the raw window handle.
111pub trait AsRawWidget {
112    /// Get the raw window handle.
113    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
136/// Trait to borrow the window handle.
137pub trait AsWidget {
138    /// Get the window handle.
139    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}