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#[derive(Clone, Copy)]
38pub struct BorrowedWindow<'a>(BorrowedWindowInner<'a>);
39
40#[allow(unreachable_patterns)]
41#[cfg(windows)]
42impl<'a> BorrowedWindow<'a> {
43 #[cfg(feature = "win32")]
51 pub unsafe fn win32(hwnd: windows_sys::Win32::Foundation::HWND) -> Self {
52 Self(BorrowedWindowInner::Win32(hwnd, PhantomData))
53 }
54
55 #[cfg(feature = "winui")]
57 pub fn winui(window: &'a winui3::Microsoft::UI::Xaml::Window) -> Self {
58 Self(BorrowedWindowInner::WinUI(window))
59 }
60
61 #[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 #[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 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 pub fn app_kit(window: &'a Retained<objc2_app_kit::NSWindow>) -> Self {
100 Self(window)
101 }
102
103 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 #[cfg(feature = "qt")]
118 pub unsafe fn qt<T>(widget: *mut T) -> Self {
119 Self(BorrowedWindowInner::Qt(widget.cast(), PhantomData))
120 }
121
122 #[cfg(feature = "gtk")]
124 pub fn gtk(window: &'a gtk4::Window) -> Self {
125 Self(BorrowedWindowInner::Gtk(window))
126 }
127
128 #[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 #[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
181pub trait AsWindow {
183 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}