1
0
Fork 0

Use wait-free spsc message chan; split off AppRunner from WindowHandle

This commit is contained in:
Joakim Frostegård 2020-11-29 16:57:34 +01:00
parent 99fdbff4e2
commit 1c81921688
4 changed files with 59 additions and 55 deletions

View file

@ -17,6 +17,7 @@ license = "MIT OR Apache-2.0"
log = "0.4.11" log = "0.4.11"
keyboard-types = { version = "0.5.0", default-features = false } keyboard-types = { version = "0.5.0", default-features = false }
raw-window-handle = "0.3.3" raw-window-handle = "0.3.3"
rtrb = "0.1.1"
static_assertions = "1.1.0" static_assertions = "1.1.0"
[target.'cfg(target_os="linux")'.dependencies] [target.'cfg(target_os="linux")'.dependencies]

View file

@ -39,21 +39,20 @@ fn main() {
parent: baseview::Parent::None, parent: baseview::Parent::None,
}; };
let handle = Window::open(window_open_options, |_| OpenWindowExample); let (mut handle, opt_app_runner) = Window::open(
window_open_options,
|_| OpenWindowExample
);
{ ::std::thread::spawn(move || {
let handle = handle.clone(); loop {
::std::thread::sleep(Duration::from_secs(5));
::std::thread::spawn(move || { if let Err(_) = handle.try_send_message(Message::Hello){
loop { println!("Failed sending message");
::std::thread::sleep(Duration::from_secs(5));
if let Err(_) = handle.try_send_message(Message::Hello){
println!("Failed sending message");
}
} }
}); }
} });
handle.app_run_blocking(); opt_app_runner.unwrap().app_run_blocking();
} }

View file

@ -3,7 +3,7 @@
/// Inspired by implementation in https://github.com/antonok-edm/vst_window /// Inspired by implementation in https://github.com/antonok-edm/vst_window
use std::ffi::c_void; use std::ffi::c_void;
use std::sync::{Arc, mpsc::{self, Sender, Receiver}}; use std::sync::Arc;
use cocoa::appkit::{ use cocoa::appkit::{
NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSApp, NSApplication, NSApplicationActivationPolicyRegular,
@ -16,6 +16,7 @@ use keyboard_types::KeyboardEvent;
use objc::{msg_send, runtime::Object, sel, sel_impl}; use objc::{msg_send, runtime::Object, sel, sel_impl};
use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle}; use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle};
use rtrb::{RingBuffer, Producer, Consumer, PushError};
use crate::{ use crate::{
Event, Parent, WindowHandler, WindowOpenOptions, Event, Parent, WindowHandler, WindowOpenOptions,
@ -42,22 +43,10 @@ pub struct Window {
} }
pub struct WindowHandle<H: WindowHandler> { pub struct AppRunner;
message_tx: Sender<H::Message>,
}
// Implement Clone manually to avoid H: Clone bound impl AppRunner {
impl <H: WindowHandler>Clone for WindowHandle<H> {
fn clone(&self) -> Self {
Self {
message_tx: self.message_tx.clone()
}
}
}
impl <H: WindowHandler>WindowHandle<H> {
pub fn app_run_blocking(self) { pub fn app_run_blocking(self) {
unsafe { unsafe {
// Get reference to already created shared NSApplication object // Get reference to already created shared NSApplication object
@ -65,28 +54,37 @@ impl <H: WindowHandler>WindowHandle<H> {
NSApp().run(); NSApp().run();
} }
} }
}
pub struct WindowHandle<H: WindowHandler> {
message_tx: Producer<H::Message>,
}
impl <H: WindowHandler>WindowHandle<H> {
pub fn try_send_message( pub fn try_send_message(
&self, &mut self,
message: H::Message message: H::Message
) -> Result<(), H::Message> { ) -> Result<(), H::Message> {
self.message_tx.send(message) self.message_tx.push(message)
.map_err(|err| err.0) .map_err(|PushError::Full(message)| message)
} }
} }
impl Window { impl Window {
pub fn open<H, B>( pub fn open<H, B>(
options: WindowOpenOptions, options: WindowOpenOptions,
build: B build: B
) -> crate::WindowHandle<H> ) -> (crate::WindowHandle<H>, Option<crate::AppRunner>)
where H: WindowHandler, where H: WindowHandler,
B: FnOnce(&mut crate::Window) -> H, B: FnOnce(&mut crate::Window) -> H,
B: Send + 'static B: Send + 'static
{ {
let _pool = unsafe { NSAutoreleasePool::new(nil) }; let _pool = unsafe { NSAutoreleasePool::new(nil) };
let mut window = match options.parent { let (mut window, opt_app_runner) = match options.parent {
Parent::WithParent(parent) => { Parent::WithParent(parent) => {
if let RawWindowHandle::MacOS(handle) = parent { if let RawWindowHandle::MacOS(handle) = parent {
let ns_view = handle.ns_view as *mut objc::runtime::Object; let ns_view = handle.ns_view as *mut objc::runtime::Object;
@ -96,10 +94,12 @@ impl Window {
let _: id = msg_send![ns_view, addSubview: subview]; let _: id = msg_send![ns_view, addSubview: subview];
Window { let window = Window {
ns_window: None, ns_window: None,
ns_view: subview, ns_view: subview,
} };
(window, None)
} }
} else { } else {
panic!("Not a macOS window"); panic!("Not a macOS window");
@ -110,10 +110,12 @@ impl Window {
create_view::<H>(&options) create_view::<H>(&options)
}; };
Window { let window = Window {
ns_window: None, ns_window: None,
ns_view, ns_view,
} };
(window, None)
}, },
Parent::None => { Parent::None => {
// It seems prudent to run NSApp() here before doing other // It seems prudent to run NSApp() here before doing other
@ -170,17 +172,19 @@ impl Window {
ns_window.setContentView_(subview); ns_window.setContentView_(subview);
Window { let window = Window {
ns_window: Some(ns_window), ns_window: Some(ns_window),
ns_view: subview, ns_view: subview,
} };
(window, Some(crate::AppRunner(AppRunner)))
} }
}, },
}; };
let window_handler = build(&mut crate::Window(&mut window)); let window_handler = build(&mut crate::Window(&mut window));
let (message_tx, message_rx) = mpsc::channel(); let (message_tx, message_rx) = RingBuffer::new(100).split();
let window_state_arc = Arc::new(WindowState { let window_state_arc = Arc::new(WindowState {
window, window,
@ -221,9 +225,11 @@ impl Window {
) )
} }
crate::WindowHandle(WindowHandle { let window_handle = crate::WindowHandle(WindowHandle {
message_tx message_tx
}) });
(window_handle, opt_app_runner)
} }
} }
@ -232,7 +238,7 @@ pub(super) struct WindowState<H: WindowHandler> {
window: Window, window: Window,
window_handler: H, window_handler: H,
keyboard_state: KeyboardState, keyboard_state: KeyboardState,
message_rx: Receiver<H::Message>, message_rx: Consumer<H::Message>,
} }
@ -249,7 +255,7 @@ impl <H: WindowHandler>WindowState<H> {
} }
pub(super) fn handle_messages(&mut self){ pub(super) fn handle_messages(&mut self){
for message in self.message_rx.try_iter(){ while let Ok(message) = self.message_rx.pop(){
self.window_handler.on_message( self.window_handler.on_message(
&mut crate::Window(&mut self.window), &mut crate::Window(&mut self.window),
message message

View file

@ -11,24 +11,22 @@ use crate::x11 as platform;
use crate::macos as platform; use crate::macos as platform;
pub struct WindowHandle<H: WindowHandler>(pub(crate) platform::WindowHandle<H>); pub struct AppRunner(pub(crate) platform::AppRunner);
// Implement Clone manually to avoid H: Clone bound impl AppRunner {
impl <H: WindowHandler>Clone for WindowHandle<H> { pub fn app_run_blocking(self){
fn clone(&self) -> Self { self.0.app_run_blocking();
WindowHandle(self.0.clone())
} }
} }
impl <H: WindowHandler>WindowHandle<H> { pub struct WindowHandle<H: WindowHandler>(pub(crate) platform::WindowHandle<H>);
pub fn app_run_blocking(self){
self.0.app_run_blocking();
}
impl <H: WindowHandler>WindowHandle<H> {
pub fn try_send_message( pub fn try_send_message(
&self, &mut self,
message: H::Message message: H::Message
) -> Result<(), H::Message> { ) -> Result<(), H::Message> {
self.0.try_send_message(message) self.0.try_send_message(message)
@ -43,7 +41,7 @@ impl <'a>Window<'a> {
pub fn open<H, B>( pub fn open<H, B>(
options: WindowOpenOptions, options: WindowOpenOptions,
build: B build: B
) -> WindowHandle<H> ) -> (WindowHandle<H>, Option<AppRunner>)
where H: WindowHandler, where H: WindowHandler,
B: FnOnce(&mut Window) -> H, B: FnOnce(&mut Window) -> H,
B: Send + 'static B: Send + 'static