#[cfg(feature = "raw-window-handle")]
use raw_window_handle::{HandleError, HasWindowHandle, WindowHandle};
cfg_if::cfg_if! {
if #[cfg(windows)] {
#[derive(Clone, Copy)]
enum BorrowedWindowInner<'a> {
#[cfg(feature = "win32")]
Win32(windows_sys::Win32::Foundation::HWND, std::marker::PhantomData<&'a ()>),
#[cfg(feature = "winui")]
WinUI(&'a winui3::Microsoft::UI::Xaml::Window),
#[cfg(not(any(feature = "win32", feature = "winui")))]
Dummy(std::convert::Infallible, std::marker::PhantomData<&'a ()>),
}
} else if #[cfg(target_os = "macos")] {
use objc2::rc::Retained;
type BorrowedWindowInner<'a> = &'a Retained<objc2_app_kit::NSWindow>;
} else if #[cfg(target_os = "android")] {
use jni::objects::JObject;
type BorrowedWindowInner<'a> = &'a JObject<'static>;
} else if #[cfg(target_os = "ios")] {
use objc2::rc::Retained;
type BorrowedWindowInner<'a> = &'a Retained<objc2_ui_kit::UIWindow>;
} else if #[cfg(target_vendor = "apple")] {
compile_error!("Other Apple platforms (like watchOS and tvOS) are not supported yet.");
} else {
#[derive(Clone, Copy)]
enum BorrowedWindowInner<'a> {
#[cfg(feature = "qt")]
Qt(*mut core::ffi::c_void, std::marker::PhantomData<&'a ()>),
#[cfg(feature = "gtk")]
Gtk(&'a gtk4::Window),
#[cfg(not(any(feature = "qt", feature = "gtk")))]
Dummy(std::convert::Infallible, std::marker::PhantomData<&'a ()>),
}
}
}
#[derive(Clone, Copy)]
pub struct BorrowedWindow<'a>(BorrowedWindowInner<'a>);
#[allow(unreachable_patterns)]
#[cfg(windows)]
impl<'a> BorrowedWindow<'a> {
#[cfg(feature = "win32")]
pub unsafe fn win32(hwnd: windows_sys::Win32::Foundation::HWND) -> Self {
Self(BorrowedWindowInner::Win32(hwnd, std::marker::PhantomData))
}
#[cfg(feature = "winui")]
pub fn winui(window: &'a winui3::Microsoft::UI::Xaml::Window) -> Self {
Self(BorrowedWindowInner::WinUI(window))
}
#[cfg(feature = "win32")]
pub fn as_win32(&self) -> windows_sys::Win32::Foundation::HWND {
match &self.0 {
BorrowedWindowInner::Win32(hwnd, ..) => *hwnd,
_ => panic!("unsupported handle type"),
}
}
#[cfg(feature = "winui")]
pub fn as_winui(&self) -> &'a winui3::Microsoft::UI::Xaml::Window {
match &self.0 {
BorrowedWindowInner::WinUI(window) => window,
_ => panic!("unsupported handle type"),
}
}
pub fn handle(&self) -> windows_core::Result<windows_sys::Win32::Foundation::HWND> {
match &self.0 {
#[cfg(feature = "win32")]
BorrowedWindowInner::Win32(hwnd, ..) => Ok(*hwnd),
#[cfg(feature = "winui")]
BorrowedWindowInner::WinUI(window) => unsafe {
use windows_core::Interface;
use winui3::IWindowNative;
Ok(window.cast::<IWindowNative>()?.WindowHandle()?.0)
},
#[cfg(not(any(feature = "win32", feature = "winui")))]
BorrowedWindowInner::Dummy(a, ..) => match *a {},
}
}
}
#[cfg(target_os = "macos")]
impl<'a> BorrowedWindow<'a> {
pub fn app_kit(window: &'a Retained<objc2_app_kit::NSWindow>) -> Self {
Self(window)
}
pub fn as_app_kit(&self) -> &'a Retained<objc2_app_kit::NSWindow> {
self.0
}
}
#[cfg(target_os = "ios")]
impl<'a> BorrowedWindow<'a> {
pub fn ui_kit(window: &'a Retained<objc2_ui_kit::UIWindow>) -> Self {
Self(window)
}
pub fn as_ui_kit(&self) -> &'a Retained<objc2_ui_kit::UIWindow> {
self.0
}
}
#[allow(unreachable_patterns)]
#[cfg(not(any(windows, target_vendor = "apple", target_os = "android")))]
impl<'a> BorrowedWindow<'a> {
#[cfg(feature = "qt")]
pub unsafe fn qt<T>(widget: *mut T) -> Self {
Self(BorrowedWindowInner::Qt(
widget.cast(),
std::marker::PhantomData,
))
}
#[cfg(feature = "gtk")]
pub fn gtk(window: &'a gtk4::Window) -> Self {
Self(BorrowedWindowInner::Gtk(window))
}
#[cfg(feature = "qt")]
pub fn as_qt<T>(&self) -> *mut T {
match &self.0 {
BorrowedWindowInner::Qt(w, ..) => (*w).cast(),
_ => panic!("unsupported handle type"),
}
}
#[cfg(feature = "gtk")]
pub fn to_gtk(&self) -> &'a gtk4::Window {
match &self.0 {
BorrowedWindowInner::Gtk(w) => w,
_ => panic!("unsupported handle type"),
}
}
}
#[cfg(target_os = "android")]
impl<'a> BorrowedWindow<'a> {
pub unsafe fn android(j_obj: &'a JObject<'static>) -> Self {
BorrowedWindow(j_obj)
}
pub fn to_android(&self) -> &'a JObject<'static> {
self.0
}
}
#[cfg(feature = "raw-window-handle")]
impl<'a> HasWindowHandle for BorrowedWindow<'a> {
#[cfg(windows)]
fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
self.handle()
.map(|hwnd| {
use raw_window_handle::{RawWindowHandle, Win32WindowHandle};
unsafe {
WindowHandle::borrow_raw(RawWindowHandle::Win32(Win32WindowHandle::new(
std::num::NonZeroIsize::new(hwnd as _).expect("HWND is null"),
)))
}
})
.map_err(|_| HandleError::NotSupported)
}
#[cfg(not(windows))]
fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
Err(HandleError::NotSupported)
}
}
pub trait AsWindow {
fn as_window(&self) -> BorrowedWindow<'_>;
}
impl AsWindow for BorrowedWindow<'_> {
fn as_window(&self) -> BorrowedWindow<'_> {
*self
}
}
impl<T: AsWindow + ?Sized> AsWindow for &T {
#[inline]
fn as_window(&self) -> BorrowedWindow<'_> {
T::as_window(self)
}
}
impl<'a, T: AsWindow + ?Sized> From<&'a T> for BorrowedWindow<'a> {
fn from(value: &'a T) -> Self {
value.as_window()
}
}
#[doc(hidden)]
pub struct MaybeBorrowedWindow<'a>(pub Option<BorrowedWindow<'a>>);
impl<'a, T: Into<BorrowedWindow<'a>>> From<T> for MaybeBorrowedWindow<'a> {
fn from(value: T) -> Self {
Self(Some(value.into()))
}
}
impl<'a, T: Into<BorrowedWindow<'a>>> From<Option<T>> for MaybeBorrowedWindow<'a> {
fn from(value: Option<T>) -> Self {
Self(value.map(|v| v.into()))
}
}
impl From<()> for MaybeBorrowedWindow<'_> {
fn from(_: ()) -> Self {
Self(None)
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_as_window {
($t:ty, $inner:ident) => {
impl $crate::AsWindow for $t {
fn as_window(&self) -> $crate::BorrowedWindow<'_> {
self.$inner.as_window()
}
}
};
}