diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f2718e919..b990777a6 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -36,6 +36,9 @@ glutin = { version = "0.27", optional = true } once_cell = "1.0" image = { version="0.23", optional = true } +[target.'cfg(target_os = "macos")'.dependencies] +cocoa = "0.24" + [build-dependencies] gl_generator = { version = "0.14", optional = true } diff --git a/examples/src/examples-common.rs b/examples/src/examples-common.rs index 06aee38aa..48b7b42dd 100644 --- a/examples/src/examples-common.rs +++ b/examples/src/examples-common.rs @@ -1,41 +1,6 @@ -/// macOS has a specific requirement that there must be a run loop running -/// on the main thread in order to open windows and use OpenGL. - -#[cfg(target_os = "macos")] -mod runloop { - use std::os::raw::c_void; - pub struct CFRunLoop(*mut c_void); - - #[link(name = "foundation", kind = "framework")] - extern "C" { - fn CFRunLoopRun(); - fn CFRunLoopGetMain() -> *mut c_void; - fn CFRunLoopStop(l: *mut c_void); - } - - impl CFRunLoop { - pub fn run() { - unsafe { - CFRunLoopRun(); - } - } - - #[doc(alias = "get_main")] - pub fn main() -> CFRunLoop { - unsafe { - let r = CFRunLoopGetMain(); - assert!(!r.is_null()); - CFRunLoop(r) - } - } - - pub fn stop(&self) { - unsafe { CFRunLoopStop(self.0) } - } - } - - unsafe impl Send for CFRunLoop {} -} +/// macOS has a specific requirement that there must be a run loop running on the main thread in +/// order to open windows and use OpenGL, and that the global NSApplication instance must be +/// initialized. /// On macOS this launches the callback function on a thread. /// On other platforms it's just executed immediately. @@ -52,16 +17,38 @@ pub fn run T + Send + 'static>(main: F) -> T where T: Send + 'static, { + use cocoa::appkit::NSApplication; + use std::thread; - let l = runloop::CFRunLoop::main(); - let t = thread::spawn(move || { - let res = main(); - l.stop(); - res - }); + unsafe { + let app = cocoa::appkit::NSApp(); + let t = thread::spawn(|| { + let res = main(); - runloop::CFRunLoop::run(); + let app = cocoa::appkit::NSApp(); + app.stop_(cocoa::base::nil); - t.join().unwrap() + // Stopping the event loop requires an actual event + let event = cocoa::appkit::NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_( + cocoa::base::nil, + cocoa::appkit::NSEventType::NSApplicationDefined, + cocoa::foundation::NSPoint { x: 0.0, y: 0.0 }, + cocoa::appkit::NSEventModifierFlags::empty(), + 0.0, + 0, + cocoa::base::nil, + cocoa::appkit::NSEventSubtype::NSApplicationActivatedEventType, + 0, + 0, + ); + app.postEvent_atStart_(event, cocoa::base::YES); + + res + }); + + app.run(); + + t.join().unwrap() + } } diff --git a/tutorials/Cargo.toml b/tutorials/Cargo.toml index 1766e42d5..a0cc23e3d 100644 --- a/tutorials/Cargo.toml +++ b/tutorials/Cargo.toml @@ -18,6 +18,9 @@ byte-slice-cast = "1" anyhow = "1" termion = { version = "1.5", optional = true } +[target.'cfg(target_os = "macos")'.dependencies] +cocoa = "0.24" + [features] tutorial5 = ["gtk", "gdk", "gst-video"] tutorial5-x11 = ["tutorial5"] diff --git a/tutorials/src/tutorials-common.rs b/tutorials/src/tutorials-common.rs index 06aee38aa..889d0c263 100644 --- a/tutorials/src/tutorials-common.rs +++ b/tutorials/src/tutorials-common.rs @@ -1,41 +1,6 @@ -/// macOS has a specific requirement that there must be a run loop running -/// on the main thread in order to open windows and use OpenGL. - -#[cfg(target_os = "macos")] -mod runloop { - use std::os::raw::c_void; - pub struct CFRunLoop(*mut c_void); - - #[link(name = "foundation", kind = "framework")] - extern "C" { - fn CFRunLoopRun(); - fn CFRunLoopGetMain() -> *mut c_void; - fn CFRunLoopStop(l: *mut c_void); - } - - impl CFRunLoop { - pub fn run() { - unsafe { - CFRunLoopRun(); - } - } - - #[doc(alias = "get_main")] - pub fn main() -> CFRunLoop { - unsafe { - let r = CFRunLoopGetMain(); - assert!(!r.is_null()); - CFRunLoop(r) - } - } - - pub fn stop(&self) { - unsafe { CFRunLoopStop(self.0) } - } - } - - unsafe impl Send for CFRunLoop {} -} +/// macOS has a specific requirement that there must be a run loop running on the main thread in +/// order to open windows and use OpenGL, and that the global NSApplication instance must be +/// initialized. /// On macOS this launches the callback function on a thread. /// On other platforms it's just executed immediately. @@ -52,16 +17,40 @@ pub fn run T + Send + 'static>(main: F) -> T where T: Send + 'static, { + use cocoa::appkit::NSApplication; + use std::thread; - let l = runloop::CFRunLoop::main(); - let t = thread::spawn(move || { - let res = main(); - l.stop(); - res - }); + unsafe { + let app = cocoa::appkit::NSApp(); + let t = thread::spawn(|| { + let res = main(); - runloop::CFRunLoop::run(); + let app = cocoa::appkit::NSApp(); + app.stop_(cocoa::base::nil); - t.join().unwrap() + // Stopping the event loop requires an actual event + let event = cocoa::appkit::NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_( + cocoa::base::nil, + cocoa::appkit::NSEventType::NSApplicationDefined, + cocoa::foundation::NSPoint { x: 0.0, y: 0.0 }, + cocoa::appkit::NSEventModifierFlags::empty(), + 0.0, + 0, + cocoa::base::nil, + cocoa::appkit::NSEventSubtype::NSApplicationActivatedEventType, + 0, + 0, + ); + app.postEvent_atStart_(event, cocoa::base::YES); + + std::process::exit(0); + + res + }); + + app.run(); + + t.join().unwrap() + } }