winio-handle 0.7.0

Window handle for winio.
Documentation
cfg_if::cfg_if! {
    if #[cfg(windows)] {
        #[derive(Clone, Copy)]
        enum BorrowedWidgetInner<'a> {
            #[cfg(feature = "win32")]
            Win32(windows_sys::Win32::Foundation::HWND, std::marker::PhantomData<&'a ()>),
            #[cfg(feature = "winui")]
            WinUI(&'a winui3::Microsoft::UI::Xaml::FrameworkElement),
            #[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 BorrowedWidgetInner<'a> = &'a Retained<objc2_app_kit::NSView>;
    } else if #[cfg(target_os = "android")] {
        use jni::objects::JObject;

        type BorrowedWidgetInner<'a> = &'a JObject<'static>;
    } else if #[cfg(target_os = "ios")] {
        use objc2::rc::Retained;

        type BorrowedWidgetInner<'a> = &'a Retained<objc2_ui_kit::UIView>;
    } else if #[cfg(target_vendor = "apple")] {
        compile_error!("Other Apple platforms (like watchOS and tvOS) are not supported yet.");
    } else {
        #[derive(Clone, Copy)]
        enum BorrowedWidgetInner<'a> {
            #[cfg(feature = "qt")]
            Qt(*mut core::ffi::c_void, std::marker::PhantomData<&'a ()>),
            #[cfg(feature = "gtk")]
            Gtk(&'a gtk4::Widget),
            #[cfg(not(any(feature = "qt", feature = "gtk")))]
            Dummy(std::convert::Infallible, std::marker::PhantomData<&'a ()>),
        }
    }
}

/// Raw widget handle.
#[derive(Clone, Copy)]
pub struct BorrowedWidget<'a>(BorrowedWidgetInner<'a>);

#[allow(unreachable_patterns)]
#[cfg(windows)]
impl<'a> BorrowedWidget<'a> {
    /// Create from Win32 `HWND`.
    ///
    /// # Safety
    ///
    /// * The caller must ensure that `hwnd` is a valid handle for the lifetime
    ///   `'a`.
    /// * `hwnd` must not be null.
    #[cfg(feature = "win32")]
    pub unsafe fn win32(hwnd: windows_sys::Win32::Foundation::HWND) -> Self {
        Self(BorrowedWidgetInner::Win32(hwnd, std::marker::PhantomData))
    }

    /// Create from WinUI `FrameworkElement`.
    #[cfg(feature = "winui")]
    pub fn winui(element: &'a winui3::Microsoft::UI::Xaml::FrameworkElement) -> Self {
        Self(BorrowedWidgetInner::WinUI(element))
    }

    /// Get Win32 `HWND`.
    #[cfg(feature = "win32")]
    pub fn as_win32(&self) -> windows_sys::Win32::Foundation::HWND {
        match &self.0 {
            BorrowedWidgetInner::Win32(hwnd, ..) => *hwnd,
            _ => panic!("unsupported handle type"),
        }
    }

    /// Get WinUI `FrameworkElement`.
    #[cfg(feature = "winui")]
    pub fn as_winui(&self) -> &winui3::Microsoft::UI::Xaml::FrameworkElement {
        match &self.0 {
            BorrowedWidgetInner::WinUI(e) => e,
            _ => panic!("unsupported handle type"),
        }
    }
}

#[cfg(target_os = "macos")]
impl<'a> BorrowedWidget<'a> {
    /// Create from `NSView`.
    pub fn app_kit(view: &'a Retained<objc2_app_kit::NSView>) -> Self {
        Self(view)
    }

    /// Get `NSView`.
    pub fn as_app_kit(&self) -> &'a Retained<objc2_app_kit::NSView> {
        self.0
    }
}

#[cfg(target_os = "ios")]
impl<'a> BorrowedWidget<'a> {
    /// Create from `UIView`.
    pub fn ui_kit(view: &'a Retained<objc2_ui_kit::UIView>) -> Self {
        Self(view)
    }

    /// Get `UIView`.
    pub fn as_ui_kit(&self) -> &'a Retained<objc2_ui_kit::UIView> {
        self.0
    }
}

#[allow(unreachable_patterns)]
#[cfg(not(any(windows, target_vendor = "apple", target_os = "android")))]
impl<'a> BorrowedWidget<'a> {
    /// Create from Qt `QWidget`.
    ///
    /// # Safety
    /// The caller must ensure that `widget` is a valid pointer for the lifetime
    /// `'a`.
    #[cfg(feature = "qt")]
    pub unsafe fn qt<T>(widget: *mut T) -> Self {
        Self(BorrowedWidgetInner::Qt(
            widget.cast(),
            std::marker::PhantomData,
        ))
    }

    /// Create from Gtk `Widget`.
    #[cfg(feature = "gtk")]
    pub fn gtk(widget: &'a gtk4::Widget) -> Self {
        Self(BorrowedWidgetInner::Gtk(widget))
    }

    /// Get Qt `QWidget`.
    #[cfg(feature = "qt")]
    pub fn as_qt<T>(&self) -> *mut T {
        match &self.0 {
            BorrowedWidgetInner::Qt(w, ..) => (*w).cast(),
            _ => panic!("unsupported handle type"),
        }
    }

    /// Get Gtk `Widget`.
    #[cfg(feature = "gtk")]
    pub fn to_gtk(&self) -> &'a gtk4::Widget {
        match &self.0 {
            BorrowedWidgetInner::Gtk(w) => w,
            _ => panic!("unsupported handle type"),
        }
    }
}

#[cfg(target_os = "android")]
impl<'a> BorrowedWidget<'a> {
    /// Create from Android `Widget`
    ///
    /// # Safety
    ///
    /// `j_obj` must be an valid `Widget`.
    pub unsafe fn android(j_obj: &'a JObject<'static>) -> Self {
        BorrowedWidget(j_obj)
    }

    /// Get Android `Widget`.
    pub fn to_android(&self) -> &'a JObject<'static> {
        self.0
    }
}

/// Trait to borrow the widget handle.
pub trait AsWidget {
    /// Get the widget handle.
    fn as_widget(&self) -> BorrowedWidget<'_>;
}

impl AsWidget for BorrowedWidget<'_> {
    fn as_widget(&self) -> BorrowedWidget<'_> {
        *self
    }
}

impl<T: AsWidget + ?Sized> AsWidget for &T {
    #[inline]
    fn as_widget(&self) -> BorrowedWidget<'_> {
        T::as_widget(self)
    }
}

impl<'a, T: AsWidget + ?Sized> From<&'a T> for BorrowedWidget<'a> {
    fn from(value: &'a T) -> Self {
        value.as_widget()
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_as_widget {
    ($t:ty, $inner:ident) => {
        impl $crate::AsWidget for $t {
            fn as_widget(&self) -> $crate::BorrowedWidget<'_> {
                self.$inner.as_widget()
            }
        }
    };
}