Avoid leaking Windows by storing Weak pointers in EventsLoop

This commit is contained in:
mitchmindtree 2017-03-19 18:19:24 +11:00
parent c6968782b1
commit 4b39f81621
3 changed files with 19 additions and 10 deletions

View file

@ -6,7 +6,7 @@ use std;
pub struct EventsLoop { pub struct EventsLoop {
pub windows: std::sync::Mutex<Vec<std::sync::Arc<Window>>>, pub windows: std::sync::Mutex<Vec<std::sync::Weak<Window>>>,
pub pending_events: std::sync::Mutex<std::collections::VecDeque<Event>>, pub pending_events: std::sync::Mutex<std::collections::VecDeque<Event>>,
modifiers: std::sync::Mutex<Modifiers>, modifiers: std::sync::Mutex<Modifiers>,
interrupted: std::sync::atomic::AtomicBool, interrupted: std::sync::atomic::AtomicBool,
@ -236,8 +236,6 @@ impl EventsLoop {
let event_type = ns_event.eventType(); let event_type = ns_event.eventType();
let ns_window = ns_event.window(); let ns_window = ns_event.window();
let window_id = super::window::get_window_id(ns_window); let window_id = super::window::get_window_id(ns_window);
let windows = self.windows.lock().unwrap();
let maybe_window = windows.iter().find(|window| window_id == window.id());
// FIXME: Document this. Why do we do this? Seems like it passes on events to window/app. // FIXME: Document this. Why do we do this? Seems like it passes on events to window/app.
// If we don't do this, window does not become main for some reason. // If we don't do this, window does not become main for some reason.
@ -246,16 +244,23 @@ impl EventsLoop {
_ => appkit::NSApp().sendEvent_(ns_event), _ => appkit::NSApp().sendEvent_(ns_event),
} }
let windows = self.windows.lock().unwrap();
let maybe_window = windows.iter()
.filter_map(std::sync::Weak::upgrade)
.find(|window| window_id == window.id());
let into_event = |window_event| Event::WindowEvent { let into_event = |window_event| Event::WindowEvent {
window_id: ::WindowId(window_id), window_id: ::WindowId(window_id),
event: window_event, event: window_event,
}; };
// Returns `Some` window if one of our windows is the key window. // Returns `Some` window if one of our windows is the key window.
let maybe_key_window = || windows.iter().find(|window| { let maybe_key_window = || windows.iter()
let is_key_window: cocoa::base::BOOL = msg_send![*window.window, isKeyWindow]; .filter_map(std::sync::Weak::upgrade)
is_key_window == cocoa::base::YES .find(|window| {
}); let is_key_window: cocoa::base::BOOL = msg_send![*window.window, isKeyWindow];
is_key_window == cocoa::base::YES
});
match event_type { match event_type {
@ -586,4 +591,4 @@ fn event_mods(event: cocoa::base::id) -> ModifiersState {
alt: flags.contains(appkit::NSAlternateKeyMask), alt: flags.contains(appkit::NSAlternateKeyMask),
logo: flags.contains(appkit::NSCommandKeyMask), logo: flags.contains(appkit::NSCommandKeyMask),
} }
} }

View file

@ -26,7 +26,8 @@ impl Window2 {
{ {
let weak_events_loop = ::std::sync::Arc::downgrade(&events_loop); let weak_events_loop = ::std::sync::Arc::downgrade(&events_loop);
let window = ::std::sync::Arc::new(try!(Window::new(weak_events_loop, attributes, pl_attribs))); let window = ::std::sync::Arc::new(try!(Window::new(weak_events_loop, attributes, pl_attribs)));
events_loop.windows.lock().unwrap().push(window.clone()); let weak_window = ::std::sync::Arc::downgrade(&window);
events_loop.windows.lock().unwrap().push(weak_window);
Ok(Window2 { window: window }) Ok(Window2 { window: window })
} }

View file

@ -174,7 +174,10 @@ impl Drop for Window {
let id = self.id(); let id = self.id();
if let Some(ev) = self.delegate.state.events_loop.upgrade() { if let Some(ev) = self.delegate.state.events_loop.upgrade() {
let mut windows = ev.windows.lock().unwrap(); let mut windows = ev.windows.lock().unwrap();
windows.retain(|w| w.id() != id) windows.retain(|w| match w.upgrade() {
Some(w) => w.id() != id,
None => true,
})
} }
} }
} }