From 8ee380864cfc5896f6e30648e335f059095be532 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 8 Mar 2022 00:21:51 +0100 Subject: [PATCH] Update for CLAP 0.20 --- Cargo.lock | 16 +-- Cargo.toml | 4 +- src/wrapper/clap/wrapper.rs | 265 +++++++++++++++--------------------- 3 files changed, 120 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a100de9..3de6889c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54a65e0d4f66f8536c98cb3ca81ca33b7e2ca43442465507a3a62291ec0d9e4" +checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.55" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" [[package]] name = "assert_no_alloc" @@ -77,7 +77,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "baseview" version = "0.1.0" -source = "git+https://github.com/robbert-vdh/baseview.git?branch=feature/mouse-event-modifiers#a8ef4ddc1c53e48a2c2ca7379f89e6573a250407" +source = "git+https://github.com/robbert-vdh/baseview.git?branch=feature/mouse-event-modifiers#8e7f854c537712a30ba388bdce8764f10b466652" dependencies = [ "cocoa", "core-foundation", @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "clap-sys" version = "0.1.0" -source = "git+https://github.com/glowcoil/clap-sys?rev=3ef7048e1d3b426a7c6b02b5d3ae18f14874d4e5#3ef7048e1d3b426a7c6b02b5d3ae18f14874d4e5" +source = "git+https://github.com/robbert-vdh/clap-sys?branch=update/clap-0.20#d795c86022e0229cb219d68675329dadf1778a86" [[package]] name = "clipboard-win" @@ -887,9 +887,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "owned_ttf_parser" diff --git a/Cargo.toml b/Cargo.toml index 5ebcd3a9..7cf08e15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,8 +42,8 @@ nih_plug_derive = { path = "nih_plug_derive" } atomic_float = "0.1" atomic_refcell = "0.1" cfg-if = "1.0" -# For CLAP 0.18 -clap-sys = { git = "https://github.com/glowcoil/clap-sys", rev = "3ef7048e1d3b426a7c6b02b5d3ae18f14874d4e5" } +# For CLAP 0.20 +clap-sys = { git = "https://github.com/robbert-vdh/clap-sys", branch = "update/clap-0.20" } crossbeam = "0.8" lazy_static = "1.4" parking_lot = "0.12" diff --git a/src/wrapper/clap/wrapper.rs b/src/wrapper/clap/wrapper.rs index db0fbb0f..c45c4151 100644 --- a/src/wrapper/clap/wrapper.rs +++ b/src/wrapper/clap/wrapper.rs @@ -20,11 +20,14 @@ use clap_sys::ext::audio_ports::{ use clap_sys::ext::audio_ports_config::{ clap_audio_ports_config, clap_plugin_audio_ports_config, CLAP_EXT_AUDIO_PORTS_CONFIG, }; -use clap_sys::ext::gui::{clap_plugin_gui, CLAP_EXT_GUI}; +use clap_sys::ext::gui::{ + clap_plugin_gui, clap_window, CLAP_EXT_GUI, CLAP_WINDOW_API_COCOA, CLAP_WINDOW_API_WIN32, + CLAP_WINDOW_API_X11, +}; use clap_sys::ext::latency::{clap_host_latency, clap_plugin_latency, CLAP_EXT_LATENCY}; use clap_sys::ext::params::{ - clap_host_params, clap_param_info, clap_plugin_params, CLAP_EXT_PARAMS, CLAP_PARAM_IS_BYPASS, - CLAP_PARAM_IS_STEPPED, + clap_host_params, clap_param_info, clap_plugin_params, CLAP_EXT_PARAMS, + CLAP_PARAM_IS_AUTOMATABLE, CLAP_PARAM_IS_BYPASS, CLAP_PARAM_IS_STEPPED, }; use clap_sys::ext::state::{clap_plugin_state, CLAP_EXT_STATE}; use clap_sys::ext::thread_check::{clap_host_thread_check, CLAP_EXT_THREAD_CHECK}; @@ -47,19 +50,12 @@ use std::cmp; use std::collections::{HashMap, VecDeque}; use std::ffi::{c_void, CStr}; use std::mem; -use std::os::raw::{c_char, c_ulong}; +use std::os::raw::c_char; use std::ptr; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::sync::{Arc, Weak}; use std::thread::{self, ThreadId}; -#[cfg(target_os = "macos")] -use clap_sys::ext::gui_cocoa::{clap_plugin_gui_cocoa, CLAP_EXT_GUI_COCOA}; -#[cfg(target_os = "windows")] -use clap_sys::ext::gui_win32::{clap_hwnd, clap_plugin_gui_win32, CLAP_EXT_GUI_WIN32}; -#[cfg(all(target_family = "unix", not(target_os = "macos")))] -use clap_sys::ext::gui_x11::{clap_plugin_gui_x11, CLAP_EXT_GUI_X11}; - use super::context::{WrapperGuiContext, WrapperProcessContext}; use super::descriptor::PluginDescriptor; use super::util::ClapPtr; @@ -153,15 +149,6 @@ pub struct Wrapper { clap_plugin_gui: clap_plugin_gui, - // These are now platform specific, but after CLAP 0.19 this will all be merged into the regular - // GUI extension - #[cfg(all(target_family = "unix", not(target_os = "macos")))] - clap_plugin_gui_x11: clap_plugin_gui_x11, - #[cfg(target_os = "macos")] - clap_plugin_gui_cocoa: clap_plugin_gui_cocoa, - #[cfg(target_os = "windows")] - clap_plugin_gui_win32: clap_plugin_gui_win32, - clap_plugin_latency: clap_plugin_latency, host_latency: AtomicRefCell>>, @@ -323,6 +310,7 @@ impl Wrapper

{ deactivate: Self::deactivate, start_processing: Self::start_processing, stop_processing: Self::stop_processing, + reset: Self::reset, process: Self::process, get_extension: Self::get_extension, on_main_thread: Self::on_main_thread, @@ -363,30 +351,21 @@ impl Wrapper

{ }, clap_plugin_gui: clap_plugin_gui { + is_api_supported: Self::ext_gui_is_api_supported, create: Self::ext_gui_create, destroy: Self::ext_gui_destroy, set_scale: Self::ext_gui_set_scale, get_size: Self::ext_gui_get_size, can_resize: Self::ext_gui_can_resize, - round_size: Self::ext_gui_round_size, + adjust_size: Self::ext_gui_adjust_size, set_size: Self::ext_gui_set_size, + set_parent: Self::ext_gui_set_parent, + set_transient: Self::ext_gui_set_transient, + suggest_title: Self::ext_gui_suggest_title, show: Self::ext_gui_show, hide: Self::ext_gui_hide, }, - #[cfg(all(target_family = "unix", not(target_os = "macos")))] - clap_plugin_gui_x11: clap_plugin_gui_x11 { - attach: Self::ext_gui_x11_attach, - }, - #[cfg(target_os = "macos")] - clap_plugin_gui_cocoa: clap_plugin_gui_cocoa { - attach: Self::ext_gui_cocoa_attach, - }, - #[cfg(target_os = "windows")] - clap_plugin_gui_win32: clap_plugin_gui_win32 { - attach: Self::ext_gui_win32_attach, - }, - clap_plugin_latency: clap_plugin_latency { get: Self::ext_latency_get, }, @@ -624,7 +603,8 @@ impl Wrapper

{ value: change.clap_plain_value, }; - (out.push_back)(out, &event.header); + let push_succesful = (out.try_push)(out, &event.header); + nih_debug_assert!(push_succesful); } } @@ -786,6 +766,10 @@ impl Wrapper

{ wrapper.is_processing.store(false, Ordering::SeqCst); } + unsafe extern "C" fn reset(_plugin: *const clap_plugin) { + // TODO: Split `Plugin::intialize()` into an initialize and a reset function + } + unsafe extern "C" fn process( plugin: *const clap_plugin, process: *const clap_process, @@ -963,21 +947,9 @@ impl Wrapper

{ let id = CStr::from_ptr(id); - // These extensions are only relevant on the respective platforms and they will be removed - // entirely in CLAP 0.19 - #[cfg(all(target_family = "unix", not(target_os = "macos")))] - if id == CStr::from_ptr(CLAP_EXT_GUI_X11) && wrapper.editor.is_some() { - return &wrapper.clap_plugin_gui_x11 as *const _ as *const c_void; - } - #[cfg(target_os = "macos")] - if id == CStr::from_ptr(CLAP_EXT_GUI_COCOA) && wrapper.editor.is_some() { - return &wrapper.clap_plugin_gui_cocoa as *const _ as *const c_void; - } - #[cfg(target_os = "windows")] - if id == CStr::from_ptr(CLAP_EXT_GUI_WIN32) && wrapper.editor.is_some() { - return &wrapper.clap_plugin_gui_win32 as *const _ as *const c_void; - } - + // TODO: Implement: + // - event_filter + // - tail if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS_CONFIG) { &wrapper.clap_plugin_audio_ports_config as *const _ as *const c_void } else if id == CStr::from_ptr(CLAP_EXT_AUDIO_PORTS) { @@ -1184,10 +1156,45 @@ impl Wrapper

{ } } - unsafe extern "C" fn ext_gui_create(plugin: *const clap_plugin) -> bool { - // This is a bit weird, because in CLAP 0.18 creating the editor window and embedding it in - // another window are separate, and those things are one and the same in our framework. So - // we'll just pretend we did something here. + unsafe extern "C" fn ext_gui_is_api_supported( + _plugin: *const clap_plugin, + api: *const c_char, + is_floating: bool, + ) -> bool { + // We don't do standalone floating windows + if is_floating { + return false; + } + + #[cfg(all(target_family = "unix", not(target_os = "macos")))] + if CStr::from_ptr(api) == CStr::from_ptr(CLAP_WINDOW_API_X11) { + return true; + } + #[cfg(target_os = "macos")] + if CStr::from_ptr(api) == CStr::from_ptr(CLAP_WINDOW_API_COCOA) { + return true; + } + #[cfg(target_os = "windows")] + if CStr::from_ptr(api) == CStr::from_ptr(CLAP_WINDOW_API_WIN32) { + return true; + } + + false + } + + unsafe extern "C" fn ext_gui_create( + plugin: *const clap_plugin, + api: *const c_char, + is_floating: bool, + ) -> bool { + // Double check this in case the host didn't + if !Self::ext_gui_is_api_supported(plugin, api, is_floating) { + return false; + } + + // In CLAP creating the editor window and embedding it in another window are separate, and + // those things are one and the same in our framework. So we'll just pretend we did + // something here. check_null_ptr!(false, plugin); let wrapper = &*(plugin as *const Self); @@ -1245,6 +1252,7 @@ impl Wrapper

{ check_null_ptr!(false, plugin, width, height); 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 scaling_factor = wrapper.editor_scaling_factor.load(Ordering::Relaxed); (*width, *height) = ( @@ -1260,12 +1268,13 @@ impl Wrapper

{ false } - unsafe extern "C" fn ext_gui_round_size( + unsafe extern "C" fn ext_gui_adjust_size( _plugin: *const clap_plugin, _width: *mut u32, _height: *mut u32, - ) { + ) -> bool { // TODO: Implement GUI resizing + false } unsafe extern "C" fn ext_gui_set_size( @@ -1287,113 +1296,35 @@ impl Wrapper

{ width == editor_width && height == editor_height } - unsafe extern "C" fn ext_gui_show(_plugin: *const clap_plugin) { - // TODO: Does this get used? Is this only for the free-standing window extension? (which we - // don't implement) This wouldn't make any sense for embedded editors. - } - - unsafe extern "C" fn ext_gui_hide(_plugin: *const clap_plugin) { - // TODO: Same as the above - } - - #[cfg(all(target_family = "unix", not(target_os = "macos")))] - unsafe extern "C" fn ext_gui_x11_attach( + unsafe extern "C" fn ext_gui_set_parent( plugin: *const clap_plugin, - // TODO: Should we do anything with the display name? - _display_name: *const c_char, - window: c_ulong, - ) -> bool { - check_null_ptr!(false, plugin); - // For this function we need the underlying Arc so we can pass it to the editor - let wrapper = Arc::from_raw(plugin as *const Self); - - let result = { - let mut editor_handle = wrapper.editor_handle.write(); - if editor_handle.is_none() { - let handle = { - let mut handle = raw_window_handle::XcbHandle::empty(); - handle.window = window as u32; - RawWindowHandle::Xcb(handle) - }; - - // This extension is only exposed when we have an editor - *editor_handle = Some(wrapper.editor.as_ref().unwrap().spawn( - ParentWindowHandle { handle }, - wrapper.clone().make_gui_context(), - )); - - true - } else { - nih_debug_assert_failure!( - "Host tried to attach editor while the editor is already attached" - ); - - false - } - }; - - // Leak the Arc again since we only needed a clone to pass to the GuiContext - let _ = Arc::into_raw(wrapper); - - result - } - - #[cfg(target_os = "macos")] - unsafe extern "C" fn ext_gui_cocoa_attach( - plugin: *const clap_plugin, - ns_view: *mut c_void, - ) -> bool { - check_null_ptr!(false, plugin, ns_view); - // For this function we need the underlying Arc so we can pass it to the editor - let wrapper = Arc::from_raw(plugin as *const Self); - - let result = { - let mut editor_handle = wrapper.editor_handle.write(); - if editor_handle.is_none() { - let handle = { - let mut handle = raw_window_handle::AppKitHandle::empty(); - handle.ns_view = ns_view; - RawWindowHandle::AppKit(handle) - }; - - // This extension is only exposed when we have an editor - *editor_handle = Some(wrapper.editor.as_ref().unwrap().spawn( - ParentWindowHandle { handle }, - wrapper.clone().make_gui_context(), - )); - - true - } else { - nih_debug_assert_failure!( - "Host tried to attach editor while the editor is already attached" - ); - - false - } - }; - - // Leak the Arc again since we only needed a clone to pass to the GuiContext - let _ = Arc::into_raw(wrapper); - - result - } - - #[cfg(target_os = "windows")] - unsafe extern "C" fn ext_gui_win32_attach( - plugin: *const clap_plugin, - window: clap_hwnd, + window: *const clap_window, ) -> bool { check_null_ptr!(false, plugin, window); // For this function we need the underlying Arc so we can pass it to the editor let wrapper = Arc::from_raw(plugin as *const Self); + let window = &*window; + let result = { let mut editor_handle = wrapper.editor_handle.write(); if editor_handle.is_none() { - let handle = { + let api = CStr::from_ptr(window.api); + let handle = if api == CStr::from_ptr(CLAP_WINDOW_API_X11) { + let mut handle = raw_window_handle::XcbHandle::empty(); + handle.window = window.specific.x11 as u32; + RawWindowHandle::Xcb(handle) + } else if api == CStr::from_ptr(CLAP_WINDOW_API_COCOA) { + let mut handle = raw_window_handle::AppKitHandle::empty(); + handle.ns_view = window.specific.cocoa; + RawWindowHandle::AppKit(handle) + } else if api == CStr::from_ptr(CLAP_WINDOW_API_WIN32) { let mut handle = raw_window_handle::Win32Handle::empty(); - handle.hwnd = window; + handle.hwnd = window.specific.win32; RawWindowHandle::Win32(handle) + } else { + nih_debug_assert_failure!("Host passed an invalid API"); + return false; }; // This extension is only exposed when we have an editor @@ -1418,6 +1349,29 @@ impl Wrapper

{ result } + unsafe extern "C" fn ext_gui_set_transient( + _plugin: *const clap_plugin, + _window: *const clap_window, + ) -> bool { + // This is only relevant for floating windows + false + } + + unsafe extern "C" fn ext_gui_suggest_title(_plugin: *const clap_plugin, _title: *const c_char) { + // This is only relevant for floating windows + } + + unsafe extern "C" fn ext_gui_show(_plugin: *const clap_plugin) -> bool { + // TODO: Does this get used? Is this only for the free-standing window extension? (which we + // don't implement) This wouldn't make any sense for embedded editors. + false + } + + unsafe extern "C" fn ext_gui_hide(_plugin: *const clap_plugin) -> bool { + // TODO: Same as the above + false + } + unsafe extern "C" fn ext_latency_get(plugin: *const clap_plugin) -> u32 { check_null_ptr!(0, plugin); let wrapper = &*(plugin as *const Self); @@ -1454,7 +1408,8 @@ impl Wrapper

{ let param_info = &mut *param_info; if param_index == wrapper.param_hashes.len() as i32 { param_info.id = *BYPASS_PARAM_HASH; - param_info.flags = CLAP_PARAM_IS_STEPPED | CLAP_PARAM_IS_BYPASS; + param_info.flags = + CLAP_PARAM_IS_STEPPED | CLAP_PARAM_IS_BYPASS | CLAP_PARAM_IS_AUTOMATABLE; param_info.cookie = ptr::null_mut(); strlcpy(&mut param_info.name, "Bypass"); strlcpy(&mut param_info.module, ""); @@ -1469,9 +1424,9 @@ impl Wrapper

{ param_info.id = *param_hash; param_info.flags = if step_count.is_some() { - CLAP_PARAM_IS_STEPPED + CLAP_PARAM_IS_STEPPED | CLAP_PARAM_IS_AUTOMATABLE } else { - 0 + CLAP_PARAM_IS_AUTOMATABLE }; param_info.cookie = ptr::null_mut(); strlcpy(&mut param_info.name, param_ptr.name());