diff --git a/src/wrapper/clap/context.rs b/src/wrapper/clap/context.rs index 8b94b09a..0841c580 100644 --- a/src/wrapper/clap/context.rs +++ b/src/wrapper/clap/context.rs @@ -1,4 +1,5 @@ use atomic_refcell::AtomicRefMut; +use crossbeam::channel; use std::collections::VecDeque; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -27,7 +28,18 @@ pub(crate) struct WrapperProcessContext<'a, P: ClapPlugin> { impl GuiContext for WrapperGuiContext

{ fn request_resize(&self) -> bool { - todo!("Implement window resizing for CLAP"); + // Bitwig and the CLAP test host require this resize to be done from the main thread, so + // we'll use a channel as a substitute for a promise here. + let (result_sender, result_receiver) = channel::bounded(1); + if !self + .wrapper + .do_maybe_async(Task::RequestResize(result_sender)) + { + nih_debug_assert_failure!("The task queue is full, dropping task..."); + return false; + } + + result_receiver.recv().expect("Main thread died?") } // All of these functions are supposed to be called from the main thread, so we'll put some diff --git a/src/wrapper/clap/wrapper.rs b/src/wrapper/clap/wrapper.rs index 50a028d9..de4be3b8 100644 --- a/src/wrapper/clap/wrapper.rs +++ b/src/wrapper/clap/wrapper.rs @@ -22,8 +22,8 @@ use clap_sys::ext::audio_ports_config::{ }; use clap_sys::ext::event_filter::{clap_plugin_event_filter, CLAP_EXT_EVENT_FILTER}; 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, + clap_host_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::note_ports::{ @@ -47,6 +47,7 @@ use clap_sys::process::{ }; use clap_sys::stream::{clap_istream, clap_ostream}; use crossbeam::atomic::AtomicCell; +use crossbeam::channel; use crossbeam::queue::ArrayQueue; use parking_lot::RwLock; use raw_window_handle::RawWindowHandle; @@ -153,6 +154,7 @@ pub struct Wrapper { clap_plugin_event_filter: clap_plugin_event_filter, clap_plugin_gui: clap_plugin_gui, + host_gui: AtomicRefCell>>, clap_plugin_latency: clap_plugin_latency, host_latency: AtomicRefCell>>, @@ -211,10 +213,13 @@ pub struct Wrapper { /// Tasks that can be sent from the plugin to be executed on the main thread in a non-blocking /// realtime safe way. Instead of using a random thread or the OS' event loop like in the Linux /// implementation, this uses [`clap_host::request_callback()`] instead. -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum Task { /// Inform the host that the latency has changed. LatencyChanged, + /// Request a resize from the main thread. The result is written back to the one element channel + /// for a lock of a proper promise type within the current set of libraries. + RequestResize(channel::Sender), } /// The types of CLAP parameter updates for events. @@ -301,6 +306,27 @@ impl MainThreadExecutor for Wrapper

{ } None => nih_debug_assert_failure!("Host does not support the latency extension"), }, + Task::RequestResize(result_sender) => { + // Both Bitwig and the CLAP test host won't accept resizes coming from a thread that + // isn't the main thread + let result = match (&*self.host_gui.borrow(), &self.editor) { + (Some(host_gui), Some(editor)) => { + let (unscaled_width, unscaled_height) = editor.size(); + let scaling_factor = self.editor_scaling_factor.load(Ordering::Relaxed); + + (host_gui.request_resize)( + &*self.host_callback, + (unscaled_width as f32 * scaling_factor).round() as u32, + (unscaled_height as f32 * scaling_factor).round() as u32, + ) + } + _ => false, + }; + + // This channel acts as a promise, there will never be more than a single value + // writen to it. + let _ = result_sender.send(result); + } }; } } @@ -494,6 +520,7 @@ impl Wrapper

{ show: Self::ext_gui_show, hide: Self::ext_gui_hide, }, + host_gui: AtomicRefCell::new(None), clap_plugin_latency: clap_plugin_latency { get: Self::ext_latency_get, @@ -898,6 +925,8 @@ impl Wrapper

{ let wrapper = &*(plugin as *const Self); // We weren't allowed to query these in the constructor, so we need to do it now intead. + *wrapper.host_gui.borrow_mut() = + query_host_extension::(&wrapper.host_callback, CLAP_EXT_GUI); *wrapper.host_latency.borrow_mut() = query_host_extension::(&wrapper.host_callback, CLAP_EXT_LATENCY); *wrapper.host_params.borrow_mut() = @@ -1580,7 +1609,7 @@ impl Wrapper

{ } unsafe extern "C" fn ext_gui_can_resize(_plugin: *const clap_plugin) -> bool { - // TODO: Implement GUI resizing + // TODO: Implement Host->Plugin GUI resizing false } @@ -1589,7 +1618,7 @@ impl Wrapper

{ _width: *mut u32, _height: *mut u32, ) -> bool { - // TODO: Implement GUI resizing + // TODO: Implement Host->Plugin GUI resizing false } @@ -1598,7 +1627,7 @@ impl Wrapper

{ width: u32, height: u32, ) -> bool { - // TODO: Implement GUI resizing + // TODO: Implement Host->Plugin GUI resizing check_null_ptr!(false, plugin); let wrapper = &*(plugin as *const Self);