diff --git a/README.md b/README.md index 06d7930e..50902361 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,9 @@ incomplete list of things that still have to be done before this can be used: - `IHostApplication::createComponent()` - `IConnectionPoint::notify()`, and support for indirectly connecting components through message passing proxies - - `IPlugView` + - The rest of `IPlugView` - `IEditController2` + - `IPlugFrame` - All other mandatory interfaces - All other optional interfaces - Fully implemented: see [this diff --git a/src/common/logging/vst3.cpp b/src/common/logging/vst3.cpp index 9a73988a..dcea2046 100644 --- a/src/common/logging/vst3.cpp +++ b/src/common/logging/vst3.cpp @@ -318,6 +318,14 @@ bool Vst3Logger::log_request(bool is_host_vst, }); } +bool Vst3Logger::log_request(bool is_host_vst, + const YaPlugView::SetFrame& request) { + return log_request_base(is_host_vst, [&](auto& message) { + message << request.owner_instance_id + << ": IPlugView::setFrame(frame = )"; + }); +} + bool Vst3Logger::log_request(bool is_host_vst, const YaPluginBase::Initialize& request) { return log_request_base(is_host_vst, [&](auto& message) { diff --git a/src/common/logging/vst3.h b/src/common/logging/vst3.h index a14fd01e..9eacc48c 100644 --- a/src/common/logging/vst3.h +++ b/src/common/logging/vst3.h @@ -97,6 +97,7 @@ class Vst3Logger { bool log_request(bool is_host_vst, const YaPlugView::GetSize&); bool log_request(bool is_host_vst, const YaPlugView::OnSize&); bool log_request(bool is_host_vst, const YaPlugView::OnFocus&); + bool log_request(bool is_host_vst, const YaPlugView::SetFrame&); bool log_request(bool is_host_vst, const YaPluginBase::Initialize&); bool log_request(bool is_host_vst, const YaPluginBase::Terminate&); bool log_request(bool is_host_vst, const YaPluginFactory::Construct&); diff --git a/src/common/serialization/vst3.h b/src/common/serialization/vst3.h index 8dd51ffc..1e399523 100644 --- a/src/common/serialization/vst3.h +++ b/src/common/serialization/vst3.h @@ -88,6 +88,7 @@ using ControlRequest = std::variant + void serialize(S& s) { + s.value8b(owner_instance_id); + s.object(plug_frame_args); + } + }; + virtual tresult PLUGIN_API setFrame(Steinberg::IPlugFrame* frame) override = 0; virtual tresult PLUGIN_API canResize() override = 0; diff --git a/src/plugin/bridges/vst3-impls/plug-view-proxy.cpp b/src/plugin/bridges/vst3-impls/plug-view-proxy.cpp index f7fb1fd9..eaa09a64 100644 --- a/src/plugin/bridges/vst3-impls/plug-view-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plug-view-proxy.cpp @@ -122,9 +122,20 @@ tresult PLUGIN_API Vst3PlugViewProxyImpl::onFocus(TBool state) { tresult PLUGIN_API Vst3PlugViewProxyImpl::setFrame(Steinberg::IPlugFrame* frame) { - // TODO: Implement - bridge.logger.log("TODO: IPlugView::setFrame()"); - return Steinberg::kNotImplemented; + if (frame) { + // We'll store the pointer for when the plugin later makes a callback to + // this component handler + plug_frame = frame; + + return bridge.send_message(YaPlugView::SetFrame{ + .owner_instance_id = owner_instance_id(), + .plug_frame_args = Vst3PlugFrameProxy::ConstructArgs( + plug_frame, owner_instance_id())}); + } else { + bridge.logger.log( + "WARNING: Null pointer passed to 'IPlugView::setFrame()'"); + return Steinberg::kInvalidArgument; + } } tresult PLUGIN_API Vst3PlugViewProxyImpl::canResize() { diff --git a/src/plugin/bridges/vst3-impls/plug-view-proxy.h b/src/plugin/bridges/vst3-impls/plug-view-proxy.h index 4e497621..0a9711f0 100644 --- a/src/plugin/bridges/vst3-impls/plug-view-proxy.h +++ b/src/plugin/bridges/vst3-impls/plug-view-proxy.h @@ -57,6 +57,13 @@ class Vst3PlugViewProxyImpl : public Vst3PlugViewProxy { tresult PLUGIN_API canResize() override; tresult PLUGIN_API checkSizeConstraint(Steinberg::ViewRect* rect) override; + /** + * The `IPlugFrame` object passed by the host passed to us in + * `IPlugView::setFrame()`. When the plugin makes a callback on the + * `IPlugFrame` proxy object, we'll pass the call through to this object. + */ + Steinberg::IPtr plug_frame; + private: Vst3PluginBridge& bridge; }; diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp index 2b196590..58ded7a1 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp @@ -342,10 +342,6 @@ tresult PLUGIN_API Vst3PluginProxyImpl::setComponentHandler( // this component handler component_handler = handler; - // Automatically converted smart pointers for when the plugin performs a - // callback later - host_application = host_context; - return bridge.send_message(YaEditController::SetComponentHandler{ .instance_id = instance_id(), .component_handler_proxy_args = diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index 261e274e..7df6f3ed 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -403,6 +403,23 @@ void Vst3Bridge::run() { return object_instances[request.owner_instance_id] .plug_view->onFocus(request.state); }, + [&](YaPlugView::SetFrame& request) + -> YaPlugView::SetFrame::Response { + // We'll create a proxy object for the `IPlugFrame` object and + // pass that to the `setFrame()` function. The lifetime of this + // object is tied to that of the actual `IPlugFrame` object + // we're passing this proxy to. + // TODO: Does this have to be run from the UI thread? Figure out + // if it does + object_instances[request.owner_instance_id].plug_frame_proxy = + Steinberg::owned(new Vst3PlugFrameProxyImpl( + *this, std::move(request.plug_frame_args))); + + return object_instances[request.owner_instance_id] + .plug_view->setFrame( + object_instances[request.owner_instance_id] + .plug_frame_proxy); + }, [&](YaPluginBase::Initialize& request) -> YaPluginBase::Initialize::Response { // We'll create a proxy object for the host context passed by diff --git a/src/wine-host/bridges/vst3.h b/src/wine-host/bridges/vst3.h index 620eb4d2..6f47761a 100644 --- a/src/wine-host/bridges/vst3.h +++ b/src/wine-host/bridges/vst3.h @@ -53,6 +53,15 @@ struct InstanceInterfaces { */ Steinberg::IPtr host_context_proxy; + /** + * After a call to `IEditController::setComponentHandler()`, we'll create a + * proxy of that component handler just like we did for the plugin object. + * When the plugin calls a function on this object, we make a callback to + * the original object provided by the host. Will be initialized with a null + * pointer until used. + */ + Steinberg::IPtr component_handler_proxy; + /** * If the host passes an `IPlugFrame` object during `IPlugView::setFrame()`, * then we'll store a proxy object here and then pass it to @@ -63,15 +72,6 @@ struct InstanceInterfaces { */ Steinberg::IPtr plug_frame_proxy; - /** - * After a call to `IEditController::setComponentHandler()`, we'll create a - * proxy of that component handler just like we did for the plugin object. - * When the plugin calls a function on this object, we make a callback to - * the original object provided by the host. Will be initialized with a null - * pointer until used. - */ - Steinberg::IPtr component_handler_proxy; - /** * The base object we cast from. */