diff --git a/examples/gain/src/lib.rs b/examples/gain/src/lib.rs index a6b6f1f8..113276d2 100644 --- a/examples/gain/src/lib.rs +++ b/examples/gain/src/lib.rs @@ -58,6 +58,10 @@ impl Plugin for Gain { ], params: GainParams::params(), has_view: true, + size: Size { + width: 256.0, + height: 256.0 + } } } @@ -336,15 +340,6 @@ impl GainView { } impl View for GainView { - fn size(&self) -> Size { - let size = self.task.with(|state, _| state.window.as_ref().unwrap().size()); - - Size { - width: size.width, - height: size.height, - } - } - fn param_changed(&mut self, id: ParamId, value: ParamValue) { self.task.with(|state, _| { state.params.set_param(id, value); diff --git a/src/format/clap/gui.rs b/src/format/clap/gui.rs index a76b63fc..f37bb228 100644 --- a/src/format/clap/gui.rs +++ b/src/format/clap/gui.rs @@ -1,22 +1,31 @@ +use std::cell::RefCell; use std::collections::HashMap; use std::ffi::{c_char, CStr}; +use std::future::Future; +use std::os::raw::c_int; use std::rc::Rc; use std::sync::Arc; -use clap_sys::ext::{gui::*, params::*}; -use clap_sys::{host::*, plugin::*}; - -use super::instance::Instance; +use super::instance::{Instance, MainThreadState}; use crate::params::{ParamId, ParamValue}; use crate::plugin::Plugin; use crate::sync::param_gestures::ParamGestures; use crate::view::{ParentWindow, RawParent, View, ViewHost, ViewHostInner}; +use clap_sys::ext::posix_fd_support::{ + clap_plugin_posix_fd_support, clap_posix_fd_flags, CLAP_POSIX_FD_READ, +}; +use clap_sys::ext::timer_support::clap_plugin_timer_support; +use clap_sys::ext::{gui::*, params::*}; +use clap_sys::id::{clap_id, CLAP_INVALID_ID}; +use clap_sys::{host::*, plugin::*}; -struct ClapViewHost { +pub struct ClapViewHost { host: *const clap_host, host_params: Option<*const clap_host_params>, param_map: Arc>, param_gestures: Arc, + #[cfg_attr(not(target_os = "linux"), allow(unused))] + timer_id: Option, } impl ViewHostInner for ClapViewHost { @@ -73,6 +82,17 @@ impl Instance

{ #[cfg(target_os = "linux")] const API: &'static CStr = CLAP_WINDOW_API_X11; + #[cfg(target_os = "linux")] + pub(crate) const TIMER_SUPPORT: clap_plugin_timer_support = clap_plugin_timer_support { + on_timer: Some(Self::timer_support_on_timer), + }; + + #[cfg(target_os = "linux")] + pub(crate) const POSIX_FD_SUPPORT: clap_plugin_posix_fd_support = + clap_plugin_posix_fd_support { + on_fd: Some(Self::posix_fd_support_on_fd), + }; + unsafe extern "C" fn gui_is_api_supported( _plugin: *const clap_plugin, api: *const c_char, @@ -113,6 +133,18 @@ impl Instance

{ let instance = &*(plugin as *const Self); let main_thread_state = &mut *instance.main_thread_state.get(); + if let Some(posix_fd_support) = (*instance.host_extensions.get()).posix_fd_support { + if let Some(fd) = main_thread_state.view.as_ref().unwrap().file_descriptor() { + (*posix_fd_support).unregister_fd.unwrap_unchecked()(instance.host, fd); + } + } + + if let Some(timer_support) = (*instance.host_extensions.get()).timer_support { + (*timer_support).unregister_timer.unwrap_unchecked()( + instance.host, main_thread_state.view_host.as_ref().unwrap().timer_id.unwrap() + ); + } + main_thread_state.view = None; } @@ -125,19 +157,11 @@ impl Instance

{ width: *mut u32, height: *mut u32, ) -> bool { - let instance = &*(plugin as *const Self); - let main_thread_state = &mut *instance.main_thread_state.get(); - - if let Some(view) = &main_thread_state.view { - let size = view.size(); - - *width = size.width.round() as u32; - *height = size.height.round() as u32; - - return true; - } + let size = P::info().size; + *width = size.width as u32; + *height = size.height as u32; - false + true } unsafe extern "C" fn gui_can_resize(_plugin: *const clap_plugin) -> bool { @@ -189,14 +213,63 @@ impl Instance

{ let instance = &*(plugin as *const Self); let main_thread_state = &mut *instance.main_thread_state.get(); - let host = ViewHost::from_inner(Rc::new(ClapViewHost { + let mut timer_id: Option = None; + #[cfg(target_os = "linux")] + { + let host_extensions = instance.host_extensions.get(); + if (*host_extensions).timer_support.is_none() + { + dbg!("missing timer support"); + return false; + } + let timer_support = (*host_extensions).timer_support.unwrap(); + const TIMER_PERIOD_MS: u32 = 16; + let mut maybe_timer_id = CLAP_INVALID_ID; + if !(*timer_support).register_timer.unwrap_unchecked()( + instance.host, + TIMER_PERIOD_MS, + &mut maybe_timer_id, + ) { + dbg!("Failed to register timer"); + return false; + } + timer_id = Some(maybe_timer_id); + } + + let view_host = Rc::new(ClapViewHost { host: instance.host, host_params: main_thread_state.host_params, param_map: Arc::clone(&instance.param_map), param_gestures: Arc::clone(&instance.param_gestures), - })); + timer_id, + }); + main_thread_state.view_host = Some(view_host); + let view_host = ViewHost::from_inner(main_thread_state.view_host.as_ref().unwrap().clone()); let parent = ParentWindow::from_raw(raw_parent); - let view = main_thread_state.plugin.view(host, &parent); + let view = main_thread_state.plugin.view(view_host, &parent); + + #[cfg(target_os = "linux")] + { + let host_extensions = instance.host_extensions.get(); + if (*host_extensions).posix_fd_support.is_none() + { + dbg!("missing fd support"); + return false; + } + let posix_fd_support = (*host_extensions).posix_fd_support.unwrap(); + + if let Some(fd) = view.file_descriptor() { + if !(*posix_fd_support).register_fd.unwrap_unchecked()( + instance.host, + fd, + CLAP_POSIX_FD_READ, + ) { + dbg!("Failed to register fd"); + return false; + } + } + } + main_thread_state.view = Some(view); true @@ -218,4 +291,39 @@ impl Instance

{ unsafe extern "C" fn gui_hide(_plugin: *const clap_plugin) -> bool { false } + + #[cfg(target_os = "linux")] + unsafe extern "C" fn timer_support_on_timer(plugin: *const clap_plugin, timer_id: clap_id) { + let instance = &*(plugin as *const Self); + let main_thread_state = unsafe { &mut *instance.main_thread_state.get() }; + + main_thread_state.view_host.as_ref().unwrap().timer_id; + + if let Some(view_host) = &mut main_thread_state.view_host { + if let Some(id) = view_host.timer_id { + if id == timer_id { + if let Some(view) = &mut main_thread_state.view { + view.poll(); + } + } + } + } + } + + #[cfg(target_os = "linux")] + pub unsafe extern "C" fn posix_fd_support_on_fd( + plugin: *const clap_plugin, + fd: i32, + _flags: clap_posix_fd_flags, + ) { + let instance = &*(plugin as *const Self); + let main_thread_state = unsafe { &mut *instance.main_thread_state.get() }; + if let Some(view) = &mut main_thread_state.view { + if let Some(fd) = view.file_descriptor() { + if fd == fd { + view.poll(); + } + } + } + } } diff --git a/src/format/clap/instance.rs b/src/format/clap/instance.rs index 09f2d686..72e9eaf5 100644 --- a/src/format/clap/instance.rs +++ b/src/format/clap/instance.rs @@ -5,15 +5,17 @@ use std::iter::zip; use std::ptr::NonNull; use std::sync::Arc; use std::{io, mem, ptr, slice}; - -use clap_sys::ext::{audio_ports::*, audio_ports_config::*, gui::*, params::*, state::*}; +use std::rc::Rc; +use clap_sys::ext::{audio_ports::*, audio_ports_config::*, gui::*, params::*, posix_fd_support, state::*}; use clap_sys::{events::*, host::*, id::*, plugin::*, process::*, stream::*}; - +use clap_sys::ext::posix_fd_support::{clap_host_posix_fd_support, clap_plugin_posix_fd_support, CLAP_EXT_POSIX_FD_SUPPORT}; +use clap_sys::ext::timer_support::{clap_host_timer_support, clap_plugin_timer_support, CLAP_EXT_TIMER_SUPPORT}; use super::host::ClapHost; use crate::buffers::{BufferData, BufferType, Buffers}; use crate::bus::{BusDir, Format}; use crate::engine::{Config, Engine}; use crate::events::{Data, Event, Events}; +use crate::format::clap::gui::ClapViewHost; use crate::host::Host; use crate::params::{ParamId, ParamInfo, ParamValue}; use crate::plugin::{Plugin, PluginInfo}; @@ -50,6 +52,7 @@ pub struct MainThreadState { pub layout_index: usize, pub plugin: P, pub view: Option, + pub view_host: Option>, } pub struct ProcessState { @@ -60,11 +63,19 @@ pub struct ProcessState { engine: Option, } +pub struct HostExtensions { + pub timer_support: Option<*const clap_host_timer_support>, + pub posix_fd_support: Option<*const clap_host_posix_fd_support>, +} + #[repr(C)] pub struct Instance { #[allow(unused)] pub clap_plugin: clap_plugin, pub host: *const clap_host, + // todo: is below comment still correct? + // Safety: We only form an &mut in init(), which must be called before any other methods + pub host_extensions: UnsafeCell, pub info: Arc, pub input_bus_map: Vec, pub output_bus_map: Vec, @@ -120,6 +131,10 @@ impl Instance

{ on_main_thread: Some(Self::on_main_thread), }, host, + host_extensions: UnsafeCell::new(HostExtensions { + timer_support: None, + posix_fd_support: None, + }), info: info.clone(), input_bus_map, output_bus_map, @@ -132,6 +147,7 @@ impl Instance

{ layout_index: 0, plugin: P::new(Host::from_inner(Arc::new(ClapHost {}))), view: None, + view_host: None, }), process_state: UnsafeCell::new(ProcessState { gesture_states: GestureStates::with_count(info.params.len()), @@ -311,6 +327,25 @@ impl Instance

{ if !host_params.is_null() { main_thread_state.host_params = Some(host_params as *const clap_host_params); } + let host_extensions = instance.host_extensions.get(); + + let timer_support = (*instance.host).get_extension.unwrap_unchecked()( + instance.host, + CLAP_EXT_TIMER_SUPPORT.as_ptr(), + ); + if !timer_support.is_null() { + // todo: dereferencing seems odd - is this okay? + (*host_extensions).timer_support = Some(timer_support as *const clap_host_timer_support); + } + + let posix_fd_support = (*instance.host).get_extension.unwrap_unchecked()( + instance.host, + CLAP_EXT_POSIX_FD_SUPPORT.as_ptr(), + ); + if !posix_fd_support.is_null() { + // todo: dereferencing seems odd - is this okay? + (*host_extensions).posix_fd_support = Some(posix_fd_support as *const clap_host_posix_fd_support); + } true } @@ -524,6 +559,18 @@ impl Instance

{ } } + // todo: adding this required making below constants public - is there + // a better way? + #[cfg(target_os = "linux")] + if id == CLAP_EXT_TIMER_SUPPORT { + return &Self::TIMER_SUPPORT as *const _ as *const c_void; + } + + #[cfg(target_os = "linux")] + if id == CLAP_EXT_POSIX_FD_SUPPORT { + return &Self::POSIX_FD_SUPPORT as *const _ as *const c_void; + } + ptr::null() } diff --git a/src/format/clap/tests.rs b/src/format/clap/tests.rs index d5328afc..a6607722 100644 --- a/src/format/clap/tests.rs +++ b/src/format/clap/tests.rs @@ -40,6 +40,10 @@ impl Plugin for TestPlugin { layouts: vec![], params: Vec::new(), has_view: false, + size: Size { + height: 0., + width: 0., + } } } fn new(_host: Host) -> Self { diff --git a/src/format/vst3/view.rs b/src/format/vst3/view.rs index 70c77c3c..93a80c92 100644 --- a/src/format/vst3/view.rs +++ b/src/format/vst3/view.rs @@ -228,21 +228,15 @@ impl IPlugViewTrait for PlugView

{ return kResultFalse; } - let main_thread_state = &*self.main_thread_state.get(); + let plugin_size = P::info().size; - if let Some(view) = &main_thread_state.view { - let view_size = view.size(); + let rect = &mut *size; + rect.left = 0; + rect.top = 0; + rect.right = plugin_size.width.round() as int32; + rect.bottom = plugin_size.height.round() as int32; - let rect = &mut *size; - rect.left = 0; - rect.top = 0; - rect.right = view_size.width.round() as int32; - rect.bottom = view_size.height.round() as int32; - - return kResultOk; - } - - kResultFalse + kResultOk } unsafe fn onSize(&self, _newSize: *mut ViewRect) -> tresult { diff --git a/src/plugin.rs b/src/plugin.rs index cb6998fa..c8c89c02 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -5,7 +5,7 @@ use crate::bus::{BusInfo, Layout}; use crate::engine::{Config, Engine}; use crate::host::Host; use crate::params::{ParamId, ParamInfo, ParamValue}; -use crate::view::{ParentWindow, View, ViewHost}; +use crate::view::{ParentWindow, Size, View, ViewHost}; pub struct PluginInfo { pub name: String, @@ -17,6 +17,7 @@ pub struct PluginInfo { pub layouts: Vec, pub params: Vec, pub has_view: bool, + pub size: Size, } #[allow(clippy::derivable_impls)] @@ -32,6 +33,10 @@ impl Default for PluginInfo { layouts: Vec::new(), params: Vec::new(), has_view: false, + size: Size { + width: 0.0, + height: 0.0 + } } } } diff --git a/src/view.rs b/src/view.rs index d9240d8d..26a83809 100644 --- a/src/view.rs +++ b/src/view.rs @@ -66,7 +66,6 @@ pub struct Size { } pub trait View: Sized + 'static { - fn size(&self) -> Size; fn param_changed(&mut self, id: ParamId, value: ParamValue); #[cfg(target_os = "linux")] fn file_descriptor(&self) -> Option; @@ -77,13 +76,6 @@ pub trait View: Sized + 'static { pub struct NoView; impl View for NoView { - fn size(&self) -> Size { - Size { - width: 0.0, - height: 0.0, - } - } - fn param_changed(&mut self, _id: ParamId, _value: ParamValue) {} fn file_descriptor(&self) -> Option {