Use objc's autoreleasepool instead of manually with NSAutoreleasePool (#1936)

Ensures the pools are released even if we panic
This commit is contained in:
Mads Marquart 2021-05-27 17:38:41 +02:00 committed by GitHub
parent 657b4fd59e
commit 982ad46c83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 47 additions and 58 deletions

View file

@ -48,7 +48,6 @@ cocoa = "0.24"
core-foundation = "0.9" core-foundation = "0.9"
core-graphics = "0.22" core-graphics = "0.22"
dispatch = "0.2.0" dispatch = "0.2.0"
scopeguard = "1.1"
[target.'cfg(target_os = "macos")'.dependencies.core-video-sys] [target.'cfg(target_os = "macos")'.dependencies.core-video-sys]
version = "0.1.4" version = "0.1.4"

View file

@ -15,11 +15,12 @@ use std::{
use cocoa::{ use cocoa::{
appkit::{NSApp, NSApplication, NSWindow}, appkit::{NSApp, NSApplication, NSWindow},
base::{id, nil}, base::{id, nil},
foundation::{NSAutoreleasePool, NSSize}, foundation::NSSize,
};
use objc::{
rc::autoreleasepool,
runtime::{Object, YES},
}; };
use objc::runtime::YES;
use objc::runtime::Object;
use crate::{ use crate::{
dpi::LogicalSize, dpi::LogicalSize,
@ -403,16 +404,16 @@ impl AppState {
}; };
let dialog_is_closing = HANDLER.dialog_is_closing.load(Ordering::SeqCst); let dialog_is_closing = HANDLER.dialog_is_closing.load(Ordering::SeqCst);
let pool = NSAutoreleasePool::new(nil); autoreleasepool(|| {
if !INTERRUPT_EVENT_LOOP_EXIT.load(Ordering::SeqCst) if !INTERRUPT_EVENT_LOOP_EXIT.load(Ordering::SeqCst)
&& !dialog_open && !dialog_open
&& !dialog_is_closing && !dialog_is_closing
{ {
let () = msg_send![app, stop: nil]; let () = msg_send![app, stop: nil];
// To stop event loop immediately, we need to post some event here. // To stop event loop immediately, we need to post some event here.
post_dummy_event(app); post_dummy_event(app);
} }
pool.drain(); });
if window_count > 0 { if window_count > 0 {
let window: id = msg_send![windows, objectAtIndex:0]; let window: id = msg_send![windows, objectAtIndex:0];

View file

@ -14,10 +14,9 @@ use std::{
use cocoa::{ use cocoa::{
appkit::{NSApp, NSEventType::NSApplicationDefined}, appkit::{NSApp, NSEventType::NSApplicationDefined},
base::{id, nil, YES}, base::{id, nil, YES},
foundation::{NSAutoreleasePool, NSPoint}, foundation::NSPoint,
}; };
use objc::rc::autoreleasepool;
use scopeguard::defer;
use crate::{ use crate::{
event::Event, event::Event,
@ -115,9 +114,9 @@ impl<T> EventLoop<T> {
let app: id = msg_send![APP_CLASS.0, sharedApplication]; let app: id = msg_send![APP_CLASS.0, sharedApplication];
let delegate = IdRef::new(msg_send![APP_DELEGATE_CLASS.0, new]); let delegate = IdRef::new(msg_send![APP_DELEGATE_CLASS.0, new]);
let pool = NSAutoreleasePool::new(nil); autoreleasepool(|| {
let _: () = msg_send![app, setDelegate:*delegate]; let _: () = msg_send![app, setDelegate:*delegate];
let _: () = msg_send![pool, drain]; });
delegate delegate
}; };
let panic_info: Rc<PanicInfo> = Default::default(); let panic_info: Rc<PanicInfo> = Default::default();
@ -162,9 +161,7 @@ impl<T> EventLoop<T> {
self._callback = Some(Rc::clone(&callback)); self._callback = Some(Rc::clone(&callback));
unsafe { autoreleasepool(|| unsafe {
let pool = NSAutoreleasePool::new(nil);
defer!(pool.drain());
let app = NSApp(); let app = NSApp();
assert_ne!(app, nil); assert_ne!(app, nil);
@ -180,7 +177,7 @@ impl<T> EventLoop<T> {
resume_unwind(panic); resume_unwind(panic);
} }
AppState::exit(); AppState::exit();
} });
} }
pub fn create_proxy(&self) -> Proxy<T> { pub fn create_proxy(&self) -> Proxy<T> {

View file

@ -1,6 +1,7 @@
use super::util::IdRef;
use cocoa::appkit::{NSApp, NSApplication, NSEventModifierFlags, NSMenu, NSMenuItem}; use cocoa::appkit::{NSApp, NSApplication, NSEventModifierFlags, NSMenu, NSMenuItem};
use cocoa::base::{nil, selector}; use cocoa::base::{nil, selector};
use cocoa::foundation::{NSAutoreleasePool, NSProcessInfo, NSString}; use cocoa::foundation::{NSProcessInfo, NSString};
use objc::{ use objc::{
rc::autoreleasepool, rc::autoreleasepool,
runtime::{Object, Sel}, runtime::{Object, Sel},
@ -13,11 +14,11 @@ struct KeyEquivalent<'a> {
pub fn initialize() { pub fn initialize() {
autoreleasepool(|| unsafe { autoreleasepool(|| unsafe {
let menubar = NSMenu::new(nil).autorelease(); let menubar = IdRef::new(NSMenu::new(nil));
let app_menu_item = NSMenuItem::new(nil).autorelease(); let app_menu_item = IdRef::new(NSMenuItem::new(nil));
menubar.addItem_(app_menu_item); menubar.addItem_(*app_menu_item);
let app = NSApp(); let app = NSApp();
app.setMainMenu_(menubar); app.setMainMenu_(*menubar);
let app_menu = NSMenu::new(nil); let app_menu = NSMenu::new(nil);
let process_name = NSProcessInfo::processInfo(nil).processName(); let process_name = NSProcessInfo::processInfo(nil).processName();

View file

@ -25,6 +25,7 @@ pub use self::{
use crate::{ use crate::{
error::OsError as RootOsError, event::DeviceId as RootDeviceId, window::WindowAttributes, error::OsError as RootOsError, event::DeviceId as RootDeviceId, window::WindowAttributes,
}; };
use objc::rc::autoreleasepool;
pub(crate) use crate::icon::NoIcon as PlatformIcon; pub(crate) use crate::icon::NoIcon as PlatformIcon;
@ -69,7 +70,7 @@ impl Window {
attributes: WindowAttributes, attributes: WindowAttributes,
pl_attribs: PlatformSpecificWindowBuilderAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes,
) -> Result<Self, RootOsError> { ) -> Result<Self, RootOsError> {
let (window, _delegate) = UnownedWindow::new(attributes, pl_attribs)?; let (window, _delegate) = autoreleasepool(|| UnownedWindow::new(attributes, pl_attribs))?;
Ok(Window { window, _delegate }) Ok(Window { window, _delegate })
} }
} }

View file

@ -8,7 +8,7 @@ use std::ops::{BitAnd, Deref};
use cocoa::{ use cocoa::{
appkit::{NSApp, NSWindowStyleMask}, appkit::{NSApp, NSWindowStyleMask},
base::{id, nil}, base::{id, nil},
foundation::{NSAutoreleasePool, NSPoint, NSRect, NSString, NSUInteger}, foundation::{NSPoint, NSRect, NSString, NSUInteger},
}; };
use core_graphics::display::CGDisplay; use core_graphics::display::CGDisplay;
use objc::runtime::{Class, Object, Sel, BOOL, YES}; use objc::runtime::{Class, Object, Sel, BOOL, YES};
@ -61,9 +61,7 @@ impl Drop for IdRef {
fn drop(&mut self) { fn drop(&mut self) {
if self.0 != nil { if self.0 != nil {
unsafe { unsafe {
let pool = NSAutoreleasePool::new(nil);
let () = msg_send![self.0, release]; let () = msg_send![self.0, release];
pool.drain();
}; };
} }
} }

View file

@ -289,7 +289,7 @@ extern "C" fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> i
let notification_center: &Object = let notification_center: &Object =
msg_send![class!(NSNotificationCenter), defaultCenter]; msg_send![class!(NSNotificationCenter), defaultCenter];
let notification_name = let notification_name =
NSString::alloc(nil).init_str("NSViewFrameDidChangeNotification"); IdRef::new(NSString::alloc(nil).init_str("NSViewFrameDidChangeNotification"));
let _: () = msg_send![ let _: () = msg_send![
notification_center, notification_center,
addObserver: this addObserver: this

View file

@ -38,11 +38,12 @@ use cocoa::{
NSRequestUserAttentionType, NSScreen, NSView, NSWindow, NSWindowButton, NSWindowStyleMask, NSRequestUserAttentionType, NSScreen, NSView, NSWindow, NSWindowButton, NSWindowStyleMask,
}, },
base::{id, nil}, base::{id, nil},
foundation::{NSAutoreleasePool, NSDictionary, NSPoint, NSRect, NSSize}, foundation::{NSDictionary, NSPoint, NSRect, NSSize},
}; };
use core_graphics::display::{CGDisplay, CGDisplayMode}; use core_graphics::display::{CGDisplay, CGDisplayMode};
use objc::{ use objc::{
declare::ClassDecl, declare::ClassDecl,
rc::autoreleasepool,
runtime::{Class, Object, Sel, BOOL, NO, YES}, runtime::{Class, Object, Sel, BOOL, NO, YES},
}; };
@ -118,8 +119,7 @@ fn create_window(
attrs: &WindowAttributes, attrs: &WindowAttributes,
pl_attrs: &PlatformSpecificWindowBuilderAttributes, pl_attrs: &PlatformSpecificWindowBuilderAttributes,
) -> Option<IdRef> { ) -> Option<IdRef> {
unsafe { autoreleasepool(|| unsafe {
let pool = NSAutoreleasePool::new(nil);
let screen = match attrs.fullscreen { let screen = match attrs.fullscreen {
Some(Fullscreen::Borderless(Some(RootMonitorHandle { inner: ref monitor }))) Some(Fullscreen::Borderless(Some(RootMonitorHandle { inner: ref monitor })))
| Some(Fullscreen::Exclusive(RootVideoMode { | Some(Fullscreen::Exclusive(RootVideoMode {
@ -241,9 +241,8 @@ fn create_window(
} }
ns_window ns_window
}); });
pool.drain();
res res
} })
} }
struct WindowClass(*const Class); struct WindowClass(*const Class);
@ -336,17 +335,11 @@ impl UnownedWindow {
} }
trace!("Creating new window"); trace!("Creating new window");
let pool = unsafe { NSAutoreleasePool::new(nil) }; let ns_window = create_window(&win_attribs, &pl_attribs)
let ns_window = create_window(&win_attribs, &pl_attribs).ok_or_else(|| { .ok_or_else(|| os_error!(OsError::CreationError("Couldn't create `NSWindow`")))?;
unsafe { pool.drain() };
os_error!(OsError::CreationError("Couldn't create `NSWindow`"))
})?;
let (ns_view, cursor_state) = let (ns_view, cursor_state) = unsafe { create_view(*ns_window, &pl_attribs) }
unsafe { create_view(*ns_window, &pl_attribs) }.ok_or_else(|| { .ok_or_else(|| os_error!(OsError::CreationError("Couldn't create `NSView`")))?;
unsafe { pool.drain() };
os_error!(OsError::CreationError("Couldn't create `NSView`"))
})?;
// Configure the new view as the "key view" for the window // Configure the new view as the "key view" for the window
unsafe { unsafe {
@ -422,8 +415,6 @@ impl UnownedWindow {
window.set_maximized(maximized); window.set_maximized(maximized);
} }
unsafe { pool.drain() };
Ok((window, delegate)) Ok((window, delegate))
} }

View file

@ -7,10 +7,11 @@ use std::{
use cocoa::{ use cocoa::{
appkit::{self, NSApplicationPresentationOptions, NSView, NSWindow}, appkit::{self, NSApplicationPresentationOptions, NSView, NSWindow},
base::{id, nil}, base::{id, nil},
foundation::{NSAutoreleasePool, NSUInteger}, foundation::NSUInteger,
}; };
use objc::{ use objc::{
declare::ClassDecl, declare::ClassDecl,
rc::autoreleasepool,
runtime::{Class, Object, Sel, BOOL, NO, YES}, runtime::{Class, Object, Sel, BOOL, NO, YES},
}; };
@ -274,11 +275,11 @@ extern "C" fn window_will_close(this: &Object, _: Sel, _: id) {
trace!("Triggered `windowWillClose:`"); trace!("Triggered `windowWillClose:`");
with_state(this, |state| unsafe { with_state(this, |state| unsafe {
// `setDelegate:` retains the previous value and then autoreleases it // `setDelegate:` retains the previous value and then autoreleases it
let pool = NSAutoreleasePool::new(nil); autoreleasepool(|| {
// Since El Capitan, we need to be careful that delegate methods can't // Since El Capitan, we need to be careful that delegate methods can't
// be called after the window closes. // be called after the window closes.
let () = msg_send![*state.ns_window, setDelegate: nil]; let () = msg_send![*state.ns_window, setDelegate: nil];
pool.drain(); });
state.emit_event(WindowEvent::Destroyed); state.emit_event(WindowEvent::Destroyed);
}); });
trace!("Completed `windowWillClose:`"); trace!("Completed `windowWillClose:`");