Move the event loop to its own module
Now that the context module is becoming larger and larger.
This commit is contained in:
parent
07d8f81f44
commit
b209c9caf3
|
@ -1,29 +1,9 @@
|
||||||
//! Different contexts the plugin can use to make callbacks to the host in different...contexts.
|
//! Different contexts the plugin can use to make callbacks to the host in different...contexts.
|
||||||
|
|
||||||
use std::sync::Weak;
|
|
||||||
|
|
||||||
#[cfg(all(target_family = "unix", not(target_os = "macos")))]
|
|
||||||
mod linux;
|
|
||||||
// For now, also use the Linux event loop on macOS so it at least compiles
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
mod linux;
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
mod windows;
|
|
||||||
|
|
||||||
#[cfg(all(target_family = "unix", not(target_os = "macos")))]
|
|
||||||
pub(crate) use self::linux::LinuxEventLoop as OsEventLoop;
|
|
||||||
// For now, also use the Linux event loop on macOS so it at least compiles
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub(crate) use self::linux::LinuxEventLoop as OsEventLoop;
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub(crate) use self::windows::WindowsEventLoop as OsEventLoop;
|
|
||||||
|
|
||||||
use crate::param::internals::ParamPtr;
|
use crate::param::internals::ParamPtr;
|
||||||
use crate::param::Param;
|
use crate::param::Param;
|
||||||
use crate::plugin::NoteEvent;
|
use crate::plugin::NoteEvent;
|
||||||
|
|
||||||
pub(crate) const TASK_QUEUE_CAPACITY: usize = 512;
|
|
||||||
|
|
||||||
// TODO: ProcessContext for parameter automation and sending events
|
// TODO: ProcessContext for parameter automation and sending events
|
||||||
|
|
||||||
/// General callbacks the plugin can make during its lifetime. This is passed to the plugin during
|
/// General callbacks the plugin can make during its lifetime. This is passed to the plugin during
|
||||||
|
@ -159,47 +139,3 @@ impl<'a> ParamSetter<'a> {
|
||||||
param.preview_plain(self.default_normalized_param_value(param))
|
param.preview_plain(self.default_normalized_param_value(param))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait describing the functionality of the platform-specific event loop that can execute tasks
|
|
||||||
/// of type `T` in executor `E`. Posting a task to the internal task queue should be realtime safe.
|
|
||||||
/// This event loop should be created during the wrapper's initial initialization on the main
|
|
||||||
/// thread.
|
|
||||||
///
|
|
||||||
/// This is never used generically, but having this as a trait will cause any missing functions on
|
|
||||||
/// an implementation to show up as compiler errors even when using a different platform. And since
|
|
||||||
/// the tasks and executor will be sent to a thread, they need to have static lifetimes.
|
|
||||||
///
|
|
||||||
/// TODO: At some point rethink the design to make it possible to have a singleton message queue for
|
|
||||||
/// all instances of a plugin.
|
|
||||||
pub(crate) trait EventLoop<T, E>
|
|
||||||
where
|
|
||||||
T: Send + 'static,
|
|
||||||
E: MainThreadExecutor<T> + 'static,
|
|
||||||
{
|
|
||||||
/// Create and start a new event loop. The thread this is called on will be designated as the
|
|
||||||
/// main thread, so this should be called when constructing the wrapper.
|
|
||||||
fn new_and_spawn(executor: Weak<E>) -> Self;
|
|
||||||
|
|
||||||
/// Either post the function to the task queue so it can be delegated to the main thread, or
|
|
||||||
/// execute the task directly if this is the main thread. This function needs to be callable at
|
|
||||||
/// any time without blocking.
|
|
||||||
///
|
|
||||||
/// If the task queue is full, then this will return false.
|
|
||||||
#[must_use]
|
|
||||||
fn do_maybe_async(&self, task: T) -> bool;
|
|
||||||
|
|
||||||
/// Whether the calling thread is the event loop's main thread. This is usually the thread the
|
|
||||||
/// event loop instance was initialized on.
|
|
||||||
fn is_main_thread(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Something that can execute tasks of type `T`.
|
|
||||||
pub(crate) trait MainThreadExecutor<T>: Send + Sync {
|
|
||||||
/// Execute a task on the current thread. This should only be called from the main thread.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// This is not actually unsafe in the typical Rust sense. But the implemnting function will
|
|
||||||
/// assume (and can only assume) that this is called from the main thread.
|
|
||||||
unsafe fn execute(&self, task: T);
|
|
||||||
}
|
|
||||||
|
|
65
src/event_loop.rs
Normal file
65
src/event_loop.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
//! An internal event loop for spooling tasks to the/a GUI thread.
|
||||||
|
|
||||||
|
use std::sync::Weak;
|
||||||
|
|
||||||
|
#[cfg(all(target_family = "unix", not(target_os = "macos")))]
|
||||||
|
mod linux;
|
||||||
|
// For now, also use the Linux event loop on macOS so it at least compiles
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
mod linux;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
mod windows;
|
||||||
|
|
||||||
|
#[cfg(all(target_family = "unix", not(target_os = "macos")))]
|
||||||
|
pub(crate) use self::linux::LinuxEventLoop as OsEventLoop;
|
||||||
|
// For now, also use the Linux event loop on macOS so it at least compiles
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub(crate) use self::linux::LinuxEventLoop as OsEventLoop;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub(crate) use self::windows::WindowsEventLoop as OsEventLoop;
|
||||||
|
|
||||||
|
pub(crate) const TASK_QUEUE_CAPACITY: usize = 512;
|
||||||
|
|
||||||
|
/// A trait describing the functionality of the platform-specific event loop that can execute tasks
|
||||||
|
/// of type `T` in executor `E`. Posting a task to the internal task queue should be realtime safe.
|
||||||
|
/// This event loop should be created during the wrapper's initial initialization on the main
|
||||||
|
/// thread.
|
||||||
|
///
|
||||||
|
/// This is never used generically, but having this as a trait will cause any missing functions on
|
||||||
|
/// an implementation to show up as compiler errors even when using a different platform. And since
|
||||||
|
/// the tasks and executor will be sent to a thread, they need to have static lifetimes.
|
||||||
|
///
|
||||||
|
/// TODO: At some point rethink the design to make it possible to have a singleton message queue for
|
||||||
|
/// all instances of a plugin.
|
||||||
|
pub(crate) trait EventLoop<T, E>
|
||||||
|
where
|
||||||
|
T: Send + 'static,
|
||||||
|
E: MainThreadExecutor<T> + 'static,
|
||||||
|
{
|
||||||
|
/// Create and start a new event loop. The thread this is called on will be designated as the
|
||||||
|
/// main thread, so this should be called when constructing the wrapper.
|
||||||
|
fn new_and_spawn(executor: Weak<E>) -> Self;
|
||||||
|
|
||||||
|
/// Either post the function to the task queue so it can be delegated to the main thread, or
|
||||||
|
/// execute the task directly if this is the main thread. This function needs to be callable at
|
||||||
|
/// any time without blocking.
|
||||||
|
///
|
||||||
|
/// If the task queue is full, then this will return false.
|
||||||
|
#[must_use]
|
||||||
|
fn do_maybe_async(&self, task: T) -> bool;
|
||||||
|
|
||||||
|
/// Whether the calling thread is the event loop's main thread. This is usually the thread the
|
||||||
|
/// event loop instance was initialized on.
|
||||||
|
fn is_main_thread(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Something that can execute tasks of type `T`.
|
||||||
|
pub(crate) trait MainThreadExecutor<T>: Send + Sync {
|
||||||
|
/// Execute a task on the current thread. This should only be called from the main thread.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This is not actually unsafe in the typical Rust sense. But the implemnting function will
|
||||||
|
/// assume (and can only assume) that this is called from the main thread.
|
||||||
|
unsafe fn execute(&self, task: T);
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ pub use plugin::{
|
||||||
// The rest is either internal or already re-exported
|
// The rest is either internal or already re-exported
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod context;
|
mod context;
|
||||||
|
mod event_loop;
|
||||||
pub mod param;
|
pub mod param;
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
pub mod wrapper;
|
pub mod wrapper;
|
||||||
|
|
|
@ -3,7 +3,8 @@ use std::collections::VecDeque;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use super::inner::{Task, WrapperInner};
|
use super::inner::{Task, WrapperInner};
|
||||||
use crate::context::{EventLoop, ProcessContext};
|
use crate::context::ProcessContext;
|
||||||
|
use crate::event_loop::EventLoop;
|
||||||
use crate::plugin::{NoteEvent, Plugin};
|
use crate::plugin::{NoteEvent, Plugin};
|
||||||
|
|
||||||
/// A [ProcessContext] implementation for the wrapper. This is a separate object so it can hold on
|
/// A [ProcessContext] implementation for the wrapper. This is a separate object so it can hold on
|
||||||
|
|
|
@ -11,7 +11,8 @@ use super::context::WrapperProcessContext;
|
||||||
use super::util::{ObjectPtr, VstPtr, BYPASS_PARAM_HASH, BYPASS_PARAM_ID};
|
use super::util::{ObjectPtr, VstPtr, BYPASS_PARAM_HASH, BYPASS_PARAM_ID};
|
||||||
use super::view::WrapperView;
|
use super::view::WrapperView;
|
||||||
use crate::buffer::Buffer;
|
use crate::buffer::Buffer;
|
||||||
use crate::context::{EventLoop, GuiContext, MainThreadExecutor, OsEventLoop};
|
use crate::context::GuiContext;
|
||||||
|
use crate::event_loop::{EventLoop, MainThreadExecutor, OsEventLoop};
|
||||||
use crate::param::internals::ParamPtr;
|
use crate::param::internals::ParamPtr;
|
||||||
use crate::plugin::{BufferConfig, BusConfig, Editor, NoteEvent, Plugin, ProcessStatus};
|
use crate::plugin::{BufferConfig, BusConfig, Editor, NoteEvent, Plugin, ProcessStatus};
|
||||||
use crate::wrapper::util::hash_param_id;
|
use crate::wrapper::util::hash_param_id;
|
||||||
|
|
Loading…
Reference in a new issue