Fix crash when closing windows

This commit is contained in:
Nathan Sobo 2021-05-05 11:34:49 -06:00
parent f7d8b6b4c0
commit 3f844bc953
4 changed files with 42 additions and 1 deletions

View file

@ -758,6 +758,10 @@ impl MutableAppContext {
(window_id, root_handle) (window_id, root_handle)
} }
pub fn remove_window(&mut self, window_id: usize) {
self.presenters_and_platform_windows.remove(&window_id);
}
fn open_platform_window(&mut self, window_id: usize) { fn open_platform_window(&mut self, window_id: usize) {
let mut window = self.platform.open_window( let mut window = self.platform.open_window(
window_id, window_id,
@ -814,6 +818,13 @@ impl MutableAppContext {
})); }));
} }
{
let mut app = self.upgrade();
window.on_close(Box::new(move || {
app.update(|ctx| ctx.remove_window(window_id));
}));
}
self.presenters_and_platform_windows self.presenters_and_platform_windows
.insert(window_id, (presenter.clone(), window)); .insert(window_id, (presenter.clone(), window));

View file

@ -61,6 +61,7 @@ unsafe fn build_classes() {
sel!(sendEvent:), sel!(sendEvent:),
send_event as extern "C" fn(&Object, Sel, id), send_event as extern "C" fn(&Object, Sel, id),
); );
decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel));
decl.register() decl.register()
}; };
@ -125,6 +126,7 @@ struct WindowState {
native_window: id, native_window: id,
event_callback: Option<Box<dyn FnMut(Event)>>, event_callback: Option<Box<dyn FnMut(Event)>>,
resize_callback: Option<Box<dyn FnMut(&mut dyn platform::WindowContext)>>, resize_callback: Option<Box<dyn FnMut(&mut dyn platform::WindowContext)>>,
close_callback: Option<Box<dyn FnOnce()>>,
synthetic_drag_counter: usize, synthetic_drag_counter: usize,
executor: Rc<executor::Foreground>, executor: Rc<executor::Foreground>,
scene_to_render: Option<Scene>, scene_to_render: Option<Scene>,
@ -184,6 +186,7 @@ impl Window {
native_window, native_window,
event_callback: None, event_callback: None,
resize_callback: None, resize_callback: None,
close_callback: None,
synthetic_drag_counter: 0, synthetic_drag_counter: 0,
executor, executor,
scene_to_render: Default::default(), scene_to_render: Default::default(),
@ -262,6 +265,10 @@ impl platform::Window for Window {
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn platform::WindowContext)>) { fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn platform::WindowContext)>) {
self.0.as_ref().borrow_mut().resize_callback = Some(callback); self.0.as_ref().borrow_mut().resize_callback = Some(callback);
} }
fn on_close(&mut self, callback: Box<dyn FnOnce()>) {
self.0.as_ref().borrow_mut().close_callback = Some(callback);
}
} }
impl platform::WindowContext for Window { impl platform::WindowContext for Window {
@ -310,7 +317,7 @@ unsafe fn get_window_state(object: &Object) -> Rc<RefCell<WindowState>> {
unsafe fn drop_window_state(object: &Object) { unsafe fn drop_window_state(object: &Object) {
let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR); let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR);
Rc::from_raw(raw as *mut WindowState); Rc::from_raw(raw as *mut RefCell<WindowState>);
} }
extern "C" fn yes(_: &Object, _: Sel) -> BOOL { extern "C" fn yes(_: &Object, _: Sel) -> BOOL {
@ -371,6 +378,22 @@ extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
} }
} }
extern "C" fn close_window(this: &Object, _: Sel) {
unsafe {
let window_state = get_window_state(this);
let close_callback = window_state
.as_ref()
.try_borrow_mut()
.ok()
.and_then(|mut window_state| window_state.close_callback.take());
if let Some(callback) = close_callback {
callback();
}
let () = msg_send![super(this, class!(NSWindow)), close];
}
}
extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id {
let window_state = unsafe { get_window_state(this) }; let window_state = unsafe { get_window_state(this) };
let window_state = window_state.as_ref().borrow(); let window_state = window_state.as_ref().borrow();

View file

@ -59,6 +59,7 @@ pub trait Dispatcher: Send + Sync {
pub trait Window: WindowContext { pub trait Window: WindowContext {
fn on_event(&mut self, callback: Box<dyn FnMut(Event)>); fn on_event(&mut self, callback: Box<dyn FnMut(Event)>);
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn WindowContext)>); fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn WindowContext)>);
fn on_close(&mut self, callback: Box<dyn FnOnce()>);
} }
pub trait WindowContext { pub trait WindowContext {

View file

@ -16,6 +16,7 @@ pub struct Window {
current_scene: Option<crate::Scene>, current_scene: Option<crate::Scene>,
event_handlers: Vec<Box<dyn FnMut(super::Event)>>, event_handlers: Vec<Box<dyn FnMut(super::Event)>>,
resize_handlers: Vec<Box<dyn FnMut(&mut dyn super::WindowContext)>>, resize_handlers: Vec<Box<dyn FnMut(&mut dyn super::WindowContext)>>,
close_handlers: Vec<Box<dyn FnOnce()>>,
} }
impl Platform { impl Platform {
@ -92,6 +93,7 @@ impl Window {
size, size,
event_handlers: Vec::new(), event_handlers: Vec::new(),
resize_handlers: Vec::new(), resize_handlers: Vec::new(),
close_handlers: Vec::new(),
scale_factor: 1.0, scale_factor: 1.0,
current_scene: None, current_scene: None,
} }
@ -130,6 +132,10 @@ impl super::Window for Window {
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn super::WindowContext)>) { fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn super::WindowContext)>) {
self.resize_handlers.push(callback); self.resize_handlers.push(callback);
} }
fn on_close(&mut self, callback: Box<dyn FnOnce()>) {
self.close_handlers.push(callback);
}
} }
pub fn platform() -> impl super::Platform { pub fn platform() -> impl super::Platform {