baseview 0.3.1

Low-level windowing system geared towards making audio plugin UIs.
Documentation
mod context;
mod cursor;
mod error;
mod keyboard;
mod view;
mod window;

use crate::platform::macos::view::BaseviewView;
use crate::wrappers::appkit::{extract_raw_window_handle, ParentWindowHandleError, View};
pub use context::WindowContext;
use dispatch2::MainThreadBound;
pub use error::Error;
use objc2::__framework_prelude::Retained;
use objc2::rc::Weak;
use objc2::{MainThreadMarker, MainThreadOnly};
use objc2_app_kit::NSView;
use raw_window_handle::{DisplayHandle, HasWindowHandle};
use std::fmt;
use std::fmt::Formatter;
pub use window::*;
pub(crate) type Result<T> = std::result::Result<T, Error>;

#[cfg(feature = "opengl")]
pub mod gl;

pub struct PlatformHandle {
    inner: MainThreadBound<Weak<View<BaseviewView>>>,
}

impl PlatformHandle {
    pub fn window_handle(&self) -> Option<raw_window_handle::WindowHandle<'_>> {
        let mtm = MainThreadMarker::new()?;
        let view = self.inner.get(mtm);

        View::window_handle_from_weak(view)
    }

    pub fn display_handle(&self) -> DisplayHandle<'_> {
        DisplayHandle::appkit()
    }
}

impl Clone for PlatformHandle {
    fn clone(&self) -> Self {
        // upstream this in objc2/dispatch2 someday
        // SAFETY: The use of this marker is only to access the thread-safe Retained impl
        let mtm = unsafe { MainThreadMarker::new_unchecked() };
        let view = self.inner.get(mtm);
        Self { inner: MainThreadBound::new(view.clone(), mtm) }
    }
}

impl fmt::Debug for PlatformHandle {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        struct PtrFmt<'a>(&'a PlatformHandle);
        impl fmt::Debug for PtrFmt<'_> {
            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
                // upstream this in objc2/dispatch2 someday
                // SAFETY: The use of this marker is only to access the thread-safe Retained impl
                let mtm = unsafe { MainThreadMarker::new_unchecked() };
                match self.0.inner.get(mtm).load() {
                    Some(retained) => fmt::Pointer::fmt(&retained, f),
                    _ => f.write_str("(gone)"),
                }
            }
        }

        f.debug_struct("PlatformHandle (AppKit)").field("ns_view", &PtrFmt(self)).finish()
    }
}

#[derive(Debug)]
pub struct ParentWindowHandle {
    view: MainThreadBound<Retained<NSView>>,
}

impl ParentWindowHandle {
    pub fn extract(
        window: &impl HasWindowHandle,
    ) -> core::result::Result<Self, ParentWindowHandleError> {
        let view = extract_raw_window_handle(window.window_handle()?)?;

        let mtm = view.mtm();
        Ok(Self { view: MainThreadBound::new(view, mtm) })
    }
}

impl Clone for ParentWindowHandle {
    fn clone(&self) -> Self {
        // SAFETY: We only use Retained::clone, which is thread-safe
        let mtm = unsafe { MainThreadMarker::new_unchecked() };
        let view = self.view.get(mtm);
        Self { view: MainThreadBound::new(view.clone(), mtm) }
    }
}

impl PartialEq for ParentWindowHandle {
    fn eq(&self, other: &Self) -> bool {
        // SAFETY: We only use Retained::eq, which is thread-safe
        let mtm = unsafe { MainThreadMarker::new_unchecked() };
        Retained::eq(self.view.get(mtm), other.view.get(mtm))
    }
}

impl Eq for ParentWindowHandle {}