Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions src/platform/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use dispatch2::MainThreadBound;
pub use error::Error;
use objc2::__framework_prelude::Retained;
use objc2::rc::Weak;
use objc2::MainThreadMarker;
use objc2::{MainThreadMarker, MainThreadOnly};
use objc2_app_kit::NSView;
use raw_window_handle::{DisplayHandle, HasWindowHandle};
use std::fmt;
Expand Down Expand Up @@ -69,9 +69,9 @@ impl fmt::Debug for PlatformHandle {
}
}

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

impl ParentWindowHandle {
Expand All @@ -80,6 +80,26 @@ impl ParentWindowHandle {
) -> core::result::Result<Self, ParentWindowHandleError> {
let view = extract_raw_window_handle(window.window_handle()?)?;

Ok(Self { view })
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 {}
4 changes: 2 additions & 2 deletions src/platform/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl WindowHandle {
let _ = NSApplication::sharedApplication(mtm);

if let Some(parent) = init.settings.parent.take() {
return Self::create_window_parented(init, parent.inner.view, mtm);
return Self::create_window_parented(init, parent.inner.view.into_inner(mtm), mtm);
}

Self::create_window_standalone(init, mtm)
Expand Down Expand Up @@ -126,7 +126,7 @@ impl WindowHandle {
let Some(view) = self.view.load() else { return Ok(()) };
let Some(view) = view.inner_ref() else { return Ok(()) };

BaseviewView::set_parent(view, new_parent.view);
BaseviewView::set_parent(view, new_parent.view.into_inner(view.mtm));

Ok(())
}
Expand Down
5 changes: 5 additions & 0 deletions src/platform/win/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ pub struct ParentWindowHandle {
handle: HWnd,
}

// SAFETY: ParentWindowHandle does not actually expose any thread-unsafe operation
unsafe impl Send for ParentWindowHandle {}
// SAFETY: ParentWindowHandle does not actually expose any thread-unsafe operation
unsafe impl Sync for ParentWindowHandle {}

impl ParentWindowHandle {
pub fn extract(
parent: &impl HasWindowHandle,
Expand Down
6 changes: 6 additions & 0 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ pub struct ParentWindowHandle {
pub(crate) inner: platform::ParentWindowHandle,
}

// Assert this is Send+Sync
const _: () = {
const fn foo<T: Send + Sync>() {}
foo::<ParentWindowHandle>();
};

impl ParentWindowHandle {
/// Grabs a handle to the given `parent_window`, to later create a child window in it.
pub fn from_window(parent_window: &impl HasWindowHandle) -> Self {
Expand Down