Skip to main content

winio_handle/
window.rs

1#[cfg(feature = "raw-window-handle")]
2use raw_window_handle::{HandleError, HasWindowHandle, WindowHandle};
3
4cfg_if::cfg_if! {
5    if #[cfg(windows)] {
6        use std::marker::PhantomData;
7
8        #[derive(Clone, Copy)]
9        enum BorrowedWindowInner<'a> {
10            #[cfg(feature = "win32")]
11            Win32(windows_sys::Win32::Foundation::HWND, PhantomData<&'a ()>),
12            #[cfg(feature = "winui")]
13            WinUI(&'a winui3::Microsoft::UI::Xaml::Window),
14            #[cfg(not(any(feature = "win32", feature = "winui")))]
15            Dummy(std::convert::Infallible, PhantomData<&'a ()>),
16        }
17    } else if #[cfg(target_os = "macos")] {
18        use objc2::rc::Retained;
19
20        type BorrowedWindowInner<'a> = &'a Retained<objc2_app_kit::NSWindow>;
21    } else {
22        use std::marker::PhantomData;
23
24        #[derive(Clone, Copy)]
25        enum BorrowedWindowInner<'a> {
26            #[cfg(feature = "qt")]
27            Qt(*mut core::ffi::c_void, PhantomData<&'a ()>),
28            #[cfg(feature = "gtk")]
29            Gtk(&'a gtk4::Window),
30            #[cfg(not(any(feature = "qt", feature = "gtk")))]
31            Dummy(std::convert::Infallible, PhantomData<&'a ()>),
32        }
33    }
34}
35
36/// Raw window handle.
37#[derive(Clone, Copy)]
38pub struct BorrowedWindow<'a>(BorrowedWindowInner<'a>);
39
40#[allow(unreachable_patterns)]
41#[cfg(windows)]
42impl<'a> BorrowedWindow<'a> {
43    /// Create from Win32 `HWND`.
44    ///
45    /// # Safety
46    ///
47    /// * The caller must ensure that `hwnd` is a valid handle for the lifetime
48    ///   `'a`.
49    /// * `hwnd` must not be null.
50    #[cfg(feature = "win32")]
51    pub unsafe fn win32(hwnd: windows_sys::Win32::Foundation::HWND) -> Self {
52        Self(BorrowedWindowInner::Win32(hwnd, PhantomData))
53    }
54
55    /// Create from WinUI `Window`.
56    #[cfg(feature = "winui")]
57    pub fn winui(window: &'a winui3::Microsoft::UI::Xaml::Window) -> Self {
58        Self(BorrowedWindowInner::WinUI(window))
59    }
60
61    /// Get Win32 `HWND`. Panic if the handle is not Win32.
62    #[cfg(feature = "win32")]
63    pub fn as_win32(&self) -> windows_sys::Win32::Foundation::HWND {
64        match &self.0 {
65            BorrowedWindowInner::Win32(hwnd, ..) => *hwnd,
66            _ => panic!("unsupported handle type"),
67        }
68    }
69
70    /// Get WinUI `Window`. Panic if the handle is not WinUI.
71    #[cfg(feature = "winui")]
72    pub fn as_winui(&self) -> &'a winui3::Microsoft::UI::Xaml::Window {
73        match &self.0 {
74            BorrowedWindowInner::WinUI(window) => window,
75            _ => panic!("unsupported handle type"),
76        }
77    }
78
79    /// Get the raw window handle.
80    pub fn handle(&self) -> windows_core::Result<windows_sys::Win32::Foundation::HWND> {
81        match &self.0 {
82            #[cfg(feature = "win32")]
83            BorrowedWindowInner::Win32(hwnd, ..) => Ok(*hwnd),
84            #[cfg(feature = "winui")]
85            BorrowedWindowInner::WinUI(window) => unsafe {
86                use windows_core::Interface;
87                use winui3::IWindowNative;
88                Ok(window.cast::<IWindowNative>()?.WindowHandle()?.0)
89            },
90            #[cfg(not(any(feature = "win32", feature = "winui")))]
91            BorrowedWindowInner::Dummy(a, ..) => match *a {},
92        }
93    }
94}
95
96#[cfg(target_os = "macos")]
97impl<'a> BorrowedWindow<'a> {
98    /// Create from `NSWindow`.
99    pub fn app_kit(window: &'a Retained<objc2_app_kit::NSWindow>) -> Self {
100        Self(window)
101    }
102
103    /// Get `NSWindow`.
104    pub fn as_app_kit(&self) -> &'a Retained<objc2_app_kit::NSWindow> {
105        self.0
106    }
107}
108
109#[allow(unreachable_patterns)]
110#[cfg(not(any(windows, target_os = "macos")))]
111impl<'a> BorrowedWindow<'a> {
112    /// Create from Qt `QWidget`.
113    ///
114    /// # Safety
115    /// The caller must ensure that `widget` is a valid pointer for the lifetime
116    /// `'a`.
117    #[cfg(feature = "qt")]
118    pub unsafe fn qt<T>(widget: *mut T) -> Self {
119        Self(BorrowedWindowInner::Qt(widget.cast(), PhantomData))
120    }
121
122    /// Create from Gtk `Window`.
123    #[cfg(feature = "gtk")]
124    pub fn gtk(window: &'a gtk4::Window) -> Self {
125        Self(BorrowedWindowInner::Gtk(window))
126    }
127
128    /// Get Qt `QWidget`.
129    #[cfg(feature = "qt")]
130    pub fn as_qt<T>(&self) -> *mut T {
131        match &self.0 {
132            BorrowedWindowInner::Qt(w, ..) => (*w).cast(),
133            _ => panic!("unsupported handle type"),
134        }
135    }
136
137    /// Get Gtk `Window`.
138    #[cfg(feature = "gtk")]
139    pub fn to_gtk(&self) -> &'a gtk4::Window {
140        match &self.0 {
141            BorrowedWindowInner::Gtk(w) => w,
142            _ => panic!("unsupported handle type"),
143        }
144    }
145}
146
147#[cfg(feature = "raw-window-handle")]
148impl<'a> HasWindowHandle for BorrowedWindow<'a> {
149    #[cfg(windows)]
150    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
151        self.handle()
152            .map(|hwnd| {
153                use raw_window_handle::{RawWindowHandle, Win32WindowHandle};
154                unsafe {
155                    WindowHandle::borrow_raw(RawWindowHandle::Win32(Win32WindowHandle::new(
156                        std::num::NonZeroIsize::new(hwnd as _).expect("HWND is null"),
157                    )))
158                }
159            })
160            .map_err(|_| HandleError::NotSupported)
161    }
162
163    #[cfg(target_os = "macos")]
164    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
165        use raw_window_handle::{AppKitWindowHandle, RawWindowHandle};
166        Ok(unsafe {
167            WindowHandle::borrow_raw(RawWindowHandle::AppKit(AppKitWindowHandle::new(
168                std::ptr::NonNull::new(Retained::as_ptr(self.0).cast_mut())
169                    .expect("NSWindow is null")
170                    .cast(),
171            )))
172        })
173    }
174
175    #[cfg(not(any(windows, target_os = "macos")))]
176    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
177        Err(HandleError::NotSupported)
178    }
179}
180
181/// Trait to borrow the window handle.
182pub trait AsWindow {
183    /// Get the window handle.
184    fn as_window(&self) -> BorrowedWindow<'_>;
185}
186
187impl AsWindow for BorrowedWindow<'_> {
188    fn as_window(&self) -> BorrowedWindow<'_> {
189        *self
190    }
191}
192
193impl<T: AsWindow + ?Sized> AsWindow for &T {
194    #[inline]
195    fn as_window(&self) -> BorrowedWindow<'_> {
196        T::as_window(self)
197    }
198}
199
200impl<'a, T: AsWindow + ?Sized> From<&'a T> for BorrowedWindow<'a> {
201    fn from(value: &'a T) -> Self {
202        value.as_window()
203    }
204}
205
206#[doc(hidden)]
207pub struct MaybeBorrowedWindow<'a>(pub Option<BorrowedWindow<'a>>);
208
209impl<'a, T: Into<BorrowedWindow<'a>>> From<T> for MaybeBorrowedWindow<'a> {
210    fn from(value: T) -> Self {
211        Self(Some(value.into()))
212    }
213}
214
215impl<'a, T: Into<BorrowedWindow<'a>>> From<Option<T>> for MaybeBorrowedWindow<'a> {
216    fn from(value: Option<T>) -> Self {
217        Self(value.map(|v| v.into()))
218    }
219}
220
221impl From<()> for MaybeBorrowedWindow<'_> {
222    fn from(_: ()) -> Self {
223        Self(None)
224    }
225}
226
227#[doc(hidden)]
228#[macro_export]
229macro_rules! impl_as_window {
230    ($t:ty, $inner:ident) => {
231        impl $crate::AsWindow for $t {
232            fn as_window(&self) -> $crate::BorrowedWindow<'_> {
233                self.$inner.as_window()
234            }
235        }
236    };
237}