Skip to content

Commit 2ce28f5

Browse files
committed
macOS: fix dropping WindowHandler
1 parent 6921e91 commit 2ce28f5

1 file changed

Lines changed: 52 additions & 17 deletions

File tree

src/platform/macos/view.rs

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use objc2_app_kit::{
2020
NSTrackingAreaOptions, NSView, NSWindow,
2121
};
2222
use objc2_foundation::{NSArray, NSNotification, NSPoint, NSRect, NSSize, NSString};
23-
use std::cell::{Cell, OnceCell};
23+
use std::cell::{Cell, RefCell};
2424
use std::rc::Rc;
2525

2626
pub enum ViewParentingType {
@@ -31,7 +31,7 @@ pub enum ViewParentingType {
3131
pub(crate) struct BaseviewView {
3232
pub(crate) state: Rc<WindowSharedState>,
3333
pub(crate) mtm: MainThreadMarker,
34-
window_handler: OnceCell<Box<dyn WindowHandler>>,
34+
window_handler: WindowHandlerContainer,
3535

3636
frame_timer: Cell<Option<TimerHandle>>,
3737
notification_center_observer: Cell<Option<NotificationCenterObserver>>,
@@ -41,7 +41,7 @@ pub(crate) struct BaseviewView {
4141
parenting: ViewParentingType,
4242

4343
#[cfg(feature = "opengl")]
44-
pub(crate) gl_context: OnceCell<super::gl::GlContext>,
44+
pub(crate) gl_context: std::cell::OnceCell<super::gl::GlContext>,
4545
}
4646

4747
impl BaseviewView {
@@ -60,12 +60,12 @@ impl BaseviewView {
6060

6161
keyboard_state: KeyboardState::new(),
6262
frame_timer: None.into(),
63-
window_handler: OnceCell::new(),
63+
window_handler: WindowHandlerContainer::new(),
6464
notification_center_observer: None.into(),
6565
parenting,
6666

6767
#[cfg(feature = "opengl")]
68-
gl_context: OnceCell::new(),
68+
gl_context: std::cell::OnceCell::new(),
6969
};
7070

7171
let view = View::new(view_rect, inner, |view| {
@@ -95,7 +95,7 @@ impl BaseviewView {
9595
let handler = builder.build(crate::WindowContext::new(context));
9696

9797
// Initialize handler
98-
let Ok(()) = view.window_handler.set(handler) else { unreachable!() };
98+
view.window_handler.set(handler);
9999

100100
// Set up anything that might trigger events to the handler
101101

@@ -129,6 +129,9 @@ impl BaseviewView {
129129
pub fn close(this: ViewRef<Self>) {
130130
this.state.closed.set(true);
131131
this.view.removeFromSuperview();
132+
this.notification_center_observer.take();
133+
this.frame_timer.take();
134+
this.window_handler.destroy();
132135

133136
if let ViewParentingType::Windowed { owned_window: parent_window, running_app } =
134137
&this.parenting
@@ -171,17 +174,11 @@ impl BaseviewView {
171174

172175
/// Trigger the event immediately and return the event status.
173176
fn trigger_event(this: ViewRef<Self>, event: Event) -> EventStatus {
174-
let Some(handler) = this.window_handler.get() else {
175-
return EventStatus::Ignored;
176-
};
177-
178-
handler.on_event(event)
177+
this.window_handler.use_handler(|h| h.on_event(event)).unwrap_or(EventStatus::Ignored)
179178
}
180179

181180
fn trigger_frame(this: ViewRef<Self>) {
182-
let Some(handler) = this.window_handler.get() else { return };
183-
184-
handler.on_frame();
181+
this.window_handler.use_handler(|h| h.on_frame());
185182
}
186183
}
187184

@@ -228,9 +225,9 @@ impl ViewImpl for BaseviewView {
228225
this.state.size.set(current_size);
229226
this.state.scale_factor.set(current_scale_factor);
230227

231-
if let Some(handler) = this.window_handler.get() {
232-
handler.resized(WindowSize::from_logical(current_size, current_scale_factor))
233-
}
228+
this.window_handler.use_handler(|h| {
229+
h.resized(WindowSize::from_logical(current_size, current_scale_factor))
230+
});
234231
}
235232
}
236233

@@ -619,3 +616,41 @@ fn on_event(this: ViewRef<BaseviewView>, event: MouseEvent) -> NSDragOperation {
619616
_ => NSDragOperation::None,
620617
}
621618
}
619+
620+
pub struct WindowHandlerContainer {
621+
inner: RefCell<Option<Box<dyn WindowHandler>>>,
622+
must_be_destroyed: Cell<bool>,
623+
}
624+
625+
impl WindowHandlerContainer {
626+
pub fn new() -> WindowHandlerContainer {
627+
Self { inner: RefCell::new(None), must_be_destroyed: false.into() }
628+
}
629+
630+
pub fn use_handler<T>(&self, user: impl FnOnce(&dyn WindowHandler) -> T) -> Option<T> {
631+
let returned = {
632+
let inner = self.inner.try_borrow().ok()?;
633+
user(inner.as_ref()?.as_ref())
634+
};
635+
636+
if self.must_be_destroyed.get() {
637+
if let Ok(mut inner) = self.inner.try_borrow_mut() {
638+
*inner = None;
639+
}
640+
}
641+
642+
Some(returned)
643+
}
644+
645+
pub fn set(&self, handler: Box<dyn WindowHandler>) {
646+
self.inner.replace(Some(handler));
647+
self.must_be_destroyed.set(false);
648+
}
649+
650+
pub fn destroy(&self) {
651+
match self.inner.try_borrow_mut() {
652+
Ok(mut inner) => *inner = None,
653+
Err(_) => self.must_be_destroyed.set(true),
654+
}
655+
}
656+
}

0 commit comments

Comments
 (0)