Use wait-free spsc message chan; split off AppRunner from WindowHandle
This commit is contained in:
parent
99fdbff4e2
commit
1c81921688
|
@ -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]
|
||||||
|
|
|
@ -39,10 +39,10 @@ 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
|
||||||
let handle = handle.clone();
|
);
|
||||||
|
|
||||||
::std::thread::spawn(move || {
|
::std::thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
|
@ -53,7 +53,6 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
handle.app_run_blocking();
|
opt_app_runner.unwrap().app_run_blocking();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
WindowHandle(self.0.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl <H: WindowHandler>WindowHandle<H> {
|
|
||||||
pub fn app_run_blocking(self){
|
pub fn app_run_blocking(self){
|
||||||
self.0.app_run_blocking();
|
self.0.app_run_blocking();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct WindowHandle<H: WindowHandler>(pub(crate) platform::WindowHandle<H>);
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
Loading…
Reference in a new issue