Drop Sync requirement for Editor
This commit is contained in:
parent
eed5a62abb
commit
a2a52e0ff1
|
@ -8,6 +8,8 @@ code then it will not be listed here.
|
|||
|
||||
## [2022-10-20]
|
||||
|
||||
- `Editor` now only requires `Send` and no longer needs `Sync`. This is not a
|
||||
breaking change, but it might be worth being aware of.
|
||||
- The `create_egui_editor()` function from `nih_plug_egui` now also takes a
|
||||
build closure to apply initialization logic to the egui context.
|
||||
- The `nih_plug::param` module has been renamed to `nih_plug::params`. Code that
|
||||
|
|
|
@ -253,7 +253,7 @@ const fn swap_vst3_uid_byte_order(mut uid: [u8; 16]) -> [u8; 16] {
|
|||
}
|
||||
|
||||
/// An editor for a [`Plugin`].
|
||||
pub trait Editor: Send + Sync {
|
||||
pub trait Editor: Send {
|
||||
/// Create an instance of the plugin's editor and embed it in the parent window. As explained in
|
||||
/// [`Plugin::editor()`], you can then read the parameter values directly from your [`Params`]
|
||||
/// object, and modifying the values can be done using the functions on the
|
||||
|
|
|
@ -59,7 +59,7 @@ use clap_sys::stream::{clap_istream, clap_ostream};
|
|||
use crossbeam::atomic::AtomicCell;
|
||||
use crossbeam::channel::{self, SendTimeoutError};
|
||||
use crossbeam::queue::ArrayQueue;
|
||||
use parking_lot::RwLock;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use raw_window_handle::RawWindowHandle;
|
||||
use std::any::Any;
|
||||
use std::cmp;
|
||||
|
@ -112,7 +112,7 @@ pub struct Wrapper<P: ClapPlugin> {
|
|||
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
||||
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
||||
/// creating an editor.
|
||||
editor: Option<Box<dyn Editor>>,
|
||||
editor: Option<Mutex<Box<dyn Editor>>>,
|
||||
/// A handle for the currently active editor instance. The plugin should implement `Drop` on
|
||||
/// this handle for its closing behavior.
|
||||
editor_handle: RwLock<Option<Box<dyn Any + Send + Sync>>>,
|
||||
|
@ -381,7 +381,7 @@ impl<P: ClapPlugin> MainThreadExecutor<Task> for Wrapper<P> {
|
|||
impl<P: ClapPlugin> Wrapper<P> {
|
||||
pub fn new(host_callback: *const clap_host) -> Arc<Self> {
|
||||
let plugin = P::default();
|
||||
let editor = plugin.editor();
|
||||
let editor = plugin.editor().map(Mutex::new);
|
||||
|
||||
// This is used to allow the plugin to restore preset data from its editor, see the comment
|
||||
// on `Self::updated_state_sender`
|
||||
|
@ -713,10 +713,18 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
|
||||
/// If there's an editor open, let it know that parameter values have changed. This should be
|
||||
/// called whenever there's been a call or multiple calls to
|
||||
/// [`update_plain_value_by_hash()[Self::update_plain_value_by_hash()`].
|
||||
/// [`update_plain_value_by_hash()[Self::update_plain_value_by_hash()`]. In the off-chance that
|
||||
/// the editor instance is currently locked then nothing will happen, and the request can safely
|
||||
/// be ignored.
|
||||
pub fn notify_param_values_changed(&self) {
|
||||
if let Some(editor) = &self.editor {
|
||||
editor.param_values_changed();
|
||||
match editor.try_lock() {
|
||||
Some(editor) => editor.param_values_changed(),
|
||||
None => nih_debug_assert_failure!(
|
||||
"The editor was locked when sending a parameter value change notification, \
|
||||
ignoring"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,7 +734,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
pub fn request_resize(&self) -> bool {
|
||||
match (&*self.host_gui.borrow(), &self.editor) {
|
||||
(Some(host_gui), Some(editor)) => {
|
||||
let (unscaled_width, unscaled_height) = editor.size();
|
||||
let (unscaled_width, unscaled_height) = editor.lock().size();
|
||||
let scaling_factor = self.editor_scaling_factor.load(Ordering::Relaxed);
|
||||
|
||||
unsafe_clap_call! {
|
||||
|
@ -2672,6 +2680,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
.editor
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.set_scale_factor(scale as f32)
|
||||
{
|
||||
wrapper
|
||||
|
@ -2692,7 +2701,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
let wrapper = &*(plugin as *const Self);
|
||||
|
||||
// For macOS the scaling factor is always 1
|
||||
let (unscaled_width, unscaled_height) = wrapper.editor.as_ref().unwrap().size();
|
||||
let (unscaled_width, unscaled_height) = wrapper.editor.as_ref().unwrap().lock().size();
|
||||
let scaling_factor = wrapper.editor_scaling_factor.load(Ordering::Relaxed);
|
||||
(*width, *height) = (
|
||||
(unscaled_width as f32 * scaling_factor).round() as u32,
|
||||
|
@ -2734,7 +2743,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
check_null_ptr!(false, plugin);
|
||||
let wrapper = &*(plugin as *const Self);
|
||||
|
||||
let (unscaled_width, unscaled_height) = wrapper.editor.as_ref().unwrap().size();
|
||||
let (unscaled_width, unscaled_height) = wrapper.editor.as_ref().unwrap().lock().size();
|
||||
let scaling_factor = wrapper.editor_scaling_factor.load(Ordering::Relaxed);
|
||||
let (editor_width, editor_height) = (
|
||||
(unscaled_width as f32 * scaling_factor).round() as u32,
|
||||
|
@ -2776,7 +2785,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
};
|
||||
|
||||
// This extension is only exposed when we have an editor
|
||||
*editor_handle = Some(wrapper.editor.as_ref().unwrap().spawn(
|
||||
*editor_handle = Some(wrapper.editor.as_ref().unwrap().lock().spawn(
|
||||
ParentWindowHandle { handle },
|
||||
wrapper.clone().make_gui_context(),
|
||||
));
|
||||
|
|
|
@ -47,7 +47,7 @@ impl<P: Plugin, B: Backend> GuiContext for WrapperGuiContext<P, B> {
|
|||
}
|
||||
|
||||
fn request_resize(&self) -> bool {
|
||||
let (unscaled_width, unscaled_height) = self.wrapper.editor.as_ref().unwrap().size();
|
||||
let (unscaled_width, unscaled_height) = self.wrapper.editor.as_ref().unwrap().lock().size();
|
||||
|
||||
// This will cause the editor to be resized at the start of the next frame
|
||||
let push_successful = self
|
||||
|
|
|
@ -2,7 +2,7 @@ use atomic_refcell::AtomicRefCell;
|
|||
use baseview::{EventStatus, Window, WindowHandler, WindowOpenOptions};
|
||||
use crossbeam::channel;
|
||||
use crossbeam::queue::ArrayQueue;
|
||||
use parking_lot::RwLock;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
use std::any::Any;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
@ -47,7 +47,7 @@ pub struct Wrapper<P: Plugin, B: Backend> {
|
|||
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
||||
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
||||
/// creating an editor.
|
||||
pub editor: Option<Arc<dyn Editor>>,
|
||||
pub editor: Option<Arc<Mutex<Box<dyn Editor>>>>,
|
||||
|
||||
config: WrapperConfig,
|
||||
|
||||
|
@ -132,7 +132,7 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
|
|||
pub fn new(backend: B, config: WrapperConfig) -> Result<Arc<Self>, WrapperError> {
|
||||
let plugin = P::default();
|
||||
let params = plugin.params();
|
||||
let editor = plugin.editor().map(Arc::from);
|
||||
let editor = plugin.editor().map(|editor| Arc::new(Mutex::new(editor)));
|
||||
|
||||
// This is used to allow the plugin to restore preset data from its editor, see the comment
|
||||
// on `Self::updated_state_sender`
|
||||
|
@ -262,11 +262,11 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
|
|||
let scaling_policy = baseview::WindowScalePolicy::SystemScaleFactor;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let scaling_policy = {
|
||||
editor.set_scale_factor(self.config.dpi_scale);
|
||||
editor.lock().set_scale_factor(self.config.dpi_scale);
|
||||
baseview::WindowScalePolicy::ScaleFactor(self.config.dpi_scale as f64)
|
||||
};
|
||||
|
||||
let (width, height) = editor.size();
|
||||
let (width, height) = editor.lock().size();
|
||||
Window::open_blocking(
|
||||
WindowOpenOptions {
|
||||
title: String::from(P::NAME),
|
||||
|
@ -282,7 +282,7 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
|
|||
// baseview does not support this yet. Once this is added, we should
|
||||
// immediately close the parent window when this happens so the loop
|
||||
// can exit.
|
||||
let editor_handle = editor.spawn(
|
||||
let editor_handle = editor.lock().spawn(
|
||||
ParentWindowHandle {
|
||||
handle: window.raw_window_handle(),
|
||||
},
|
||||
|
@ -477,10 +477,18 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
|
|||
);
|
||||
}
|
||||
|
||||
/// Tell the editor that the parameter values have changed, if the plugin has an editor.
|
||||
/// Tell the editor that the parameter values have changed, if the plugin has an editor. In the
|
||||
/// off-chance that the editor instance is currently locked then nothing will happen, and the
|
||||
/// request can safely be ignored.
|
||||
fn notify_param_values_changed(&self) {
|
||||
if let Some(editor) = &self.editor {
|
||||
editor.param_values_changed();
|
||||
match editor.try_lock() {
|
||||
Some(editor) => editor.param_values_changed(),
|
||||
None => nih_debug_assert_failure!(
|
||||
"The editor was locked when sending a parameter value change notification, \
|
||||
ignoring"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use atomic_refcell::AtomicRefCell;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use crossbeam::channel::{self, SendTimeoutError};
|
||||
use parking_lot::RwLock;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
@ -37,7 +37,7 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
|||
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
||||
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
||||
/// creating an editor.
|
||||
pub editor: Option<Arc<dyn Editor>>,
|
||||
pub editor: Option<Arc<Mutex<Box<dyn Editor>>>>,
|
||||
|
||||
/// The host's [`IComponentHandler`] instance, if passed through
|
||||
/// [`IEditController::set_component_handler`].
|
||||
|
@ -190,7 +190,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
|||
#[allow(unused_unsafe)]
|
||||
pub fn new() -> Arc<Self> {
|
||||
let plugin = P::default();
|
||||
let editor = plugin.editor().map(Arc::from);
|
||||
let editor = plugin.editor().map(|editor| Arc::new(Mutex::new(editor)));
|
||||
|
||||
// This is used to allow the plugin to restore preset data from its editor, see the comment
|
||||
// on `Self::updated_state_sender`
|
||||
|
@ -372,10 +372,18 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
|||
|
||||
/// If there's an editor open, let it know that parameter values have changed. This should be
|
||||
/// called whenever there's been a call or multiple calls to
|
||||
/// [`set_normalized_value_by_hash()[Self::set_normalized_value_by_hash()`].
|
||||
/// [`set_normalized_value_by_hash()[Self::set_normalized_value_by_hash()`]. In the off-chance
|
||||
/// that the editor instance is currently locked then nothing will happen, and the request can
|
||||
/// safely be ignored.
|
||||
pub fn notify_param_values_changed(&self) {
|
||||
if let Some(editor) = &self.editor {
|
||||
editor.param_values_changed();
|
||||
match editor.try_lock() {
|
||||
Some(editor) => editor.param_values_changed(),
|
||||
None => nih_debug_assert_failure!(
|
||||
"The editor was locked when sending a parameter value change notification, \
|
||||
ignoring"
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use atomic_float::AtomicF32;
|
||||
use parking_lot::RwLock;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use raw_window_handle::RawWindowHandle;
|
||||
use std::any::Any;
|
||||
use std::ffi::{c_void, CStr};
|
||||
|
@ -52,7 +52,7 @@ struct RunLoopEventHandlerWrapper<P: Vst3Plugin>(std::marker::PhantomData<P>);
|
|||
#[VST3(implements(IPlugView, IPlugViewContentScaleSupport))]
|
||||
pub(crate) struct WrapperView<P: Vst3Plugin> {
|
||||
inner: Arc<WrapperInner<P>>,
|
||||
editor: Arc<dyn Editor>,
|
||||
editor: Arc<Mutex<Box<dyn Editor>>>,
|
||||
editor_handle: RwLock<Option<Box<dyn Any>>>,
|
||||
|
||||
/// The `IPlugFrame` instance passed by the host during [IPlugView::set_frame()].
|
||||
|
@ -99,7 +99,7 @@ struct RunLoopEventHandler<P: Vst3Plugin> {
|
|||
}
|
||||
|
||||
impl<P: Vst3Plugin> WrapperView<P> {
|
||||
pub fn new(inner: Arc<WrapperInner<P>>, editor: Arc<dyn Editor>) -> Box<Self> {
|
||||
pub fn new(inner: Arc<WrapperInner<P>>, editor: Arc<Mutex<Box<dyn Editor>>>) -> Box<Self> {
|
||||
Self::allocate(
|
||||
inner,
|
||||
editor,
|
||||
|
@ -132,7 +132,7 @@ impl<P: Vst3Plugin> WrapperView<P> {
|
|||
|
||||
match &*self.plug_frame.read() {
|
||||
Some(plug_frame) => {
|
||||
let (unscaled_width, unscaled_height) = self.editor.size();
|
||||
let (unscaled_width, unscaled_height) = self.editor.lock().size();
|
||||
let scaling_factor = self.scaling_factor.load(Ordering::Relaxed);
|
||||
let mut size = ViewRect {
|
||||
right: (unscaled_width as f32 * scaling_factor).round() as i32,
|
||||
|
@ -314,7 +314,7 @@ impl<P: Vst3Plugin> IPlugView for WrapperView<P> {
|
|||
}
|
||||
};
|
||||
|
||||
*editor_handle = Some(self.editor.spawn(
|
||||
*editor_handle = Some(self.editor.lock().spawn(
|
||||
ParentWindowHandle { handle },
|
||||
self.inner.clone().make_gui_context(),
|
||||
));
|
||||
|
@ -376,7 +376,7 @@ impl<P: Vst3Plugin> IPlugView for WrapperView<P> {
|
|||
// TODO: This is technically incorrect during resizing, this should still report the old
|
||||
// size until `.on_size()` has been called. We should probably only bother fixing this
|
||||
// if it turns out to be an issue.
|
||||
let (unscaled_width, unscaled_height) = self.editor.size();
|
||||
let (unscaled_width, unscaled_height) = self.editor.lock().size();
|
||||
let scaling_factor = self.scaling_factor.load(Ordering::Relaxed);
|
||||
let size = &mut *size;
|
||||
size.left = 0;
|
||||
|
@ -391,7 +391,7 @@ impl<P: Vst3Plugin> IPlugView for WrapperView<P> {
|
|||
check_null_ptr!(new_size);
|
||||
|
||||
// TODO: Implement Host->Plugin resizing
|
||||
let (unscaled_width, unscaled_height) = self.editor.size();
|
||||
let (unscaled_width, unscaled_height) = self.editor.lock().size();
|
||||
let scaling_factor = self.scaling_factor.load(Ordering::Relaxed);
|
||||
let (editor_width, editor_height) = (
|
||||
(unscaled_width as f32 * scaling_factor).round() as i32,
|
||||
|
@ -470,7 +470,7 @@ impl<P: Vst3Plugin> IPlugViewContentScaleSupport for WrapperView<P> {
|
|||
return kResultFalse;
|
||||
}
|
||||
|
||||
if self.editor.set_scale_factor(factor) {
|
||||
if self.editor.lock().set_scale_factor(factor) {
|
||||
self.scaling_factor.store(factor, Ordering::Relaxed);
|
||||
kResultOk
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue