forked from mirrors/gstreamer-rs
examples/tutorials: fix macOS run() wrapper terminating too early
Using terminate() kills the whole process instead of just stopping the event loop, so we're back to the 'old' way. However, if the provided function finishes too early, that can also fail (will call stop() on a not-yet-running NSApp). Creating a delegate and waiting for the callback makes sure NSApp is running before the actual main() is called. Also, for whatever reason only tutorials were changed to use terminate(). Now both tutorials and examples are using identical code. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1378>
This commit is contained in:
parent
047f4a3f75
commit
446bb7ec3e
4 changed files with 92 additions and 8 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -507,6 +507,7 @@ dependencies = [
|
||||||
"image",
|
"image",
|
||||||
"memfd",
|
"memfd",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
|
"objc",
|
||||||
"pango",
|
"pango",
|
||||||
"pangocairo",
|
"pangocairo",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
|
|
|
@ -52,6 +52,7 @@ windows = { version = "0.52", features=["Win32_Graphics_Direct3D11",
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
cocoa = "0.25"
|
cocoa = "0.25"
|
||||||
|
objc = "0.2.7"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
gl_generator = { version = "0.14", optional = true }
|
gl_generator = { version = "0.14", optional = true }
|
||||||
|
|
|
@ -17,13 +17,47 @@ pub fn run<T, F: FnOnce() -> T + Send + 'static>(main: F) -> T
|
||||||
where
|
where
|
||||||
T: Send + 'static,
|
T: Send + 'static,
|
||||||
{
|
{
|
||||||
use std::thread;
|
use std::{
|
||||||
|
ffi::c_void,
|
||||||
|
sync::mpsc::{channel, Sender},
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
use cocoa::appkit::NSApplication;
|
use cocoa::{
|
||||||
|
appkit::{NSApplication, NSWindow},
|
||||||
|
base::id,
|
||||||
|
delegate,
|
||||||
|
};
|
||||||
|
use objc::{
|
||||||
|
class, msg_send,
|
||||||
|
runtime::{Object, Sel},
|
||||||
|
sel, sel_impl,
|
||||||
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let app = cocoa::appkit::NSApp();
|
let app = cocoa::appkit::NSApp();
|
||||||
let t = thread::spawn(|| {
|
let (send, recv) = channel::<()>();
|
||||||
|
|
||||||
|
extern "C" fn on_finish_launching(this: &Object, _cmd: Sel, _notification: id) {
|
||||||
|
let send = unsafe {
|
||||||
|
let send_pointer = *this.get_ivar::<*const c_void>("send");
|
||||||
|
let boxed = Box::from_raw(send_pointer as *mut Sender<()>);
|
||||||
|
*boxed
|
||||||
|
};
|
||||||
|
send.send(()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let delegate = delegate!("AppDelegate", {
|
||||||
|
app: id = app,
|
||||||
|
send: *const c_void = Box::into_raw(Box::new(send)) as *const c_void,
|
||||||
|
(applicationDidFinishLaunching:) => on_finish_launching as extern fn(&Object, Sel, id)
|
||||||
|
});
|
||||||
|
app.setDelegate_(delegate);
|
||||||
|
|
||||||
|
let t = thread::spawn(move || {
|
||||||
|
// Wait for the NSApp to launch to avoid possibly calling stop_() too early
|
||||||
|
recv.recv().unwrap();
|
||||||
|
|
||||||
let res = main();
|
let res = main();
|
||||||
|
|
||||||
let app = cocoa::appkit::NSApp();
|
let app = cocoa::appkit::NSApp();
|
||||||
|
|
|
@ -17,18 +17,66 @@ pub fn run<T, F: FnOnce() -> T + Send + 'static>(main: F) -> T
|
||||||
where
|
where
|
||||||
T: Send + 'static,
|
T: Send + 'static,
|
||||||
{
|
{
|
||||||
use std::thread;
|
use std::{
|
||||||
|
ffi::c_void,
|
||||||
|
sync::mpsc::{channel, Sender},
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
use cocoa::appkit::NSApplication;
|
use cocoa::{
|
||||||
use objc::{msg_send, sel, sel_impl};
|
appkit::{NSApplication, NSWindow},
|
||||||
|
base::id,
|
||||||
|
delegate,
|
||||||
|
};
|
||||||
|
use objc::{
|
||||||
|
class, msg_send,
|
||||||
|
runtime::{Object, Sel},
|
||||||
|
sel, sel_impl,
|
||||||
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let app = cocoa::appkit::NSApp();
|
let app = cocoa::appkit::NSApp();
|
||||||
let t = thread::spawn(|| {
|
let (send, recv) = channel::<()>();
|
||||||
|
|
||||||
|
extern "C" fn on_finish_launching(this: &Object, _cmd: Sel, _notification: id) {
|
||||||
|
let send = unsafe {
|
||||||
|
let send_pointer = *this.get_ivar::<*const c_void>("send");
|
||||||
|
let boxed = Box::from_raw(send_pointer as *mut Sender<()>);
|
||||||
|
*boxed
|
||||||
|
};
|
||||||
|
send.send(()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let delegate = delegate!("AppDelegate", {
|
||||||
|
app: id = app,
|
||||||
|
send: *const c_void = Box::into_raw(Box::new(send)) as *const c_void,
|
||||||
|
(applicationDidFinishLaunching:) => on_finish_launching as extern fn(&Object, Sel, id)
|
||||||
|
});
|
||||||
|
app.setDelegate_(delegate);
|
||||||
|
|
||||||
|
let t = thread::spawn(move || {
|
||||||
|
// Wait for the NSApp to launch to avoid possibly calling stop_() too early
|
||||||
|
recv.recv().unwrap();
|
||||||
|
|
||||||
let res = main();
|
let res = main();
|
||||||
|
|
||||||
let app = cocoa::appkit::NSApp();
|
let app = cocoa::appkit::NSApp();
|
||||||
let _: () = msg_send![app, terminate: cocoa::base::nil];
|
app.stop_(cocoa::base::nil);
|
||||||
|
|
||||||
|
// 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
|
res
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue