Merge pull request #40 from zed-industries/close-window

Correctly handle closing windows and removing entities
This commit is contained in:
Nathan Sobo
2021-05-08 09:06:54 -06:00
committed by GitHub
15 changed files with 425 additions and 386 deletions
+322 -266
View File
File diff suppressed because it is too large Load Diff
+13
View File
@@ -347,7 +347,20 @@ impl platform::Platform for MacPlatform {
}
fn quit(&self) {
// Quitting the app causes us to close windows, which invokes `Window::on_close` callbacks
// synchronously before this method terminates. If we call `Platform::quit` while holding a
// borrow of the app state (which most of the time we will do), we will end up
// double-borrowing the app state in the `on_close` callbacks for our open windows. To solve
// this, we make quitting the application asynchronous so that we aren't holding borrows to
// the app state on the stack when we actually terminate the app.
use super::dispatcher::{dispatch_async_f, dispatch_get_main_queue};
unsafe {
dispatch_async_f(dispatch_get_main_queue(), ptr::null_mut(), Some(quit));
}
unsafe extern "C" fn quit(_: *mut c_void) {
let app = NSApplication::sharedApplication(nil);
let _: () = msg_send![app, terminate: nil];
}
+27 -1
View File
@@ -62,6 +62,7 @@ unsafe fn build_classes() {
sel!(sendEvent:),
send_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(sel!(close), close_window as extern "C" fn(&Object, Sel));
decl.register()
};
@@ -126,6 +127,7 @@ struct WindowState {
native_window: id,
event_callback: Option<Box<dyn FnMut(Event)>>,
resize_callback: Option<Box<dyn FnMut(&mut dyn platform::WindowContext)>>,
close_callback: Option<Box<dyn FnOnce()>>,
synthetic_drag_counter: usize,
executor: Rc<executor::Foreground>,
scene_to_render: Option<Scene>,
@@ -186,6 +188,7 @@ impl Window {
native_window,
event_callback: None,
resize_callback: None,
close_callback: None,
synthetic_drag_counter: 0,
executor,
scene_to_render: Default::default(),
@@ -265,6 +268,10 @@ impl platform::Window for Window {
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn platform::WindowContext)>) {
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 {
@@ -313,7 +320,7 @@ unsafe fn get_window_state(object: &Object) -> Rc<RefCell<WindowState>> {
unsafe fn drop_window_state(object: &Object) {
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 {
@@ -392,6 +399,25 @@ extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
}
}
extern "C" fn close_window(this: &Object, _: Sel) {
unsafe {
let close_callback = {
let window_state = get_window_state(this);
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 {
let window_state = unsafe { get_window_state(this) };
let window_state = window_state.as_ref().borrow();
+1
View File
@@ -70,6 +70,7 @@ pub trait Dispatcher: Send + Sync {
pub trait Window: WindowContext {
fn on_event(&mut self, callback: Box<dyn FnMut(Event)>);
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn WindowContext)>);
fn on_close(&mut self, callback: Box<dyn FnOnce()>);
}
pub trait WindowContext {
+6
View File
@@ -23,6 +23,7 @@ pub struct Window {
current_scene: Option<crate::Scene>,
event_handlers: Vec<Box<dyn FnMut(super::Event)>>,
resize_handlers: Vec<Box<dyn FnMut(&mut dyn super::WindowContext)>>,
close_handlers: Vec<Box<dyn FnOnce()>>,
}
impl Platform {
@@ -119,6 +120,7 @@ impl Window {
size,
event_handlers: Vec::new(),
resize_handlers: Vec::new(),
close_handlers: Vec::new(),
scale_factor: 1.0,
current_scene: None,
}
@@ -157,6 +159,10 @@ impl super::Window for Window {
fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn super::WindowContext)>) {
self.resize_handlers.push(callback);
}
fn on_close(&mut self, callback: Box<dyn FnOnce()>) {
self.close_handlers.push(callback);
}
}
pub(crate) fn platform() -> Platform {
+7 -6
View File
@@ -35,7 +35,7 @@ impl Presenter {
) -> Self {
Self {
window_id,
rendered_views: app.render_views(window_id).unwrap(),
rendered_views: app.render_views(window_id),
parents: HashMap::new(),
font_cache,
text_layout_cache,
@@ -55,15 +55,16 @@ impl Presenter {
path
}
pub fn invalidate(&mut self, invalidation: WindowInvalidation, app: &AppContext) {
pub fn invalidate(&mut self, mut invalidation: WindowInvalidation, app: &AppContext) {
for view_id in invalidation.removed {
invalidation.updated.remove(&view_id);
self.rendered_views.remove(&view_id);
self.parents.remove(&view_id);
}
for view_id in invalidation.updated {
self.rendered_views
.insert(view_id, app.render_view(self.window_id, view_id).unwrap());
}
for view_id in invalidation.removed {
self.rendered_views.remove(&view_id);
self.parents.remove(&view_id);
}
}
pub fn build_scene(