diff --git a/src/wine-host/bridges/vst3-impls/plug-frame-proxy.cpp b/src/wine-host/bridges/vst3-impls/plug-frame-proxy.cpp index f7026d25..f1e2b933 100644 --- a/src/wine-host/bridges/vst3-impls/plug-frame-proxy.cpp +++ b/src/wine-host/bridges/vst3-impls/plug-frame-proxy.cpp @@ -52,8 +52,18 @@ Vst3PlugFrameProxyImpl::resizeView(Steinberg::IPlugView* /*view*/, // We have to use this special sending function here so we can handle // calls to `IPlugView::onSize()` from this same thread (the UI thread). // See the docstring for more information. - return bridge_.send_mutually_recursive_message(YaPlugFrame::ResizeView{ - .owner_instance_id = owner_instance_id(), .new_size = *newSize}); + const tresult result = + bridge_.send_mutually_recursive_message(YaPlugFrame::ResizeView{ + .owner_instance_id = owner_instance_id(), .new_size = *newSize}); + + // Some hosts (like Carla) don't call onSize() after accepting a + // resizeView() request. This causes the plugin to not know about its + // new size, so it doesn't draw beyond the original size. Call the + // plugin's onSize() ourselves to ensure it knows the new size. If the + // host already called onSize(), this will be a harmless duplicate call. + bridge_.notify_plugin_on_new_size(owner_instance_id(), *newSize); + + return result; } else { std::cerr << "WARNING: Null pointer passed to 'IPlugFrame::resizeView()'" diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index d2eec2f5..b48548e8 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -1388,6 +1388,26 @@ bool Vst3Bridge::resize_editor(size_t instance_id, } } +void Vst3Bridge::notify_plugin_on_new_size(size_t instance_id, + Steinberg::ViewRect& new_size) { + const auto& [instance, _] = get_instance(instance_id); + + if (instance.plug_view_instance) { + // Skip if the host already called onSize() with this size during + // resizeView(). This is detected by checking if last_set_size already + // matches new_size (the OnSize handler updates last_set_size). + if (instance.last_set_size.getWidth() == new_size.getWidth() && + instance.last_set_size.getHeight() == new_size.getHeight()) { + return; + } + + instance.plug_view_instance->plug_view->onSize(&new_size); + + // Update last_set_size so getSize() returns consistent values + instance.last_set_size = new_size; + } +} + void Vst3Bridge::register_context_menu(Vst3ContextMenuProxyImpl& context_menu) { const auto& [owner_instance, _] = get_instance(context_menu.owner_instance_id()); diff --git a/src/wine-host/bridges/vst3.h b/src/wine-host/bridges/vst3.h index 75054893..3bef4c36 100644 --- a/src/wine-host/bridges/vst3.h +++ b/src/wine-host/bridges/vst3.h @@ -318,6 +318,14 @@ class Vst3Bridge : public HostBridge { */ bool resize_editor(size_t instance_id, const Steinberg::ViewRect& new_size); + /** + * Notify the plugin of its new size by calling `IPlugView::onSize()`. + * This is called after `resize_editor()` for hosts that don't call + * `onSize()` after accepting a `resizeView()` request (like Carla). + */ + void notify_plugin_on_new_size(size_t instance_id, + Steinberg::ViewRect& new_size); + /** * Register a context with with `context_menu`'s ID and owner in * `object_instances`. This will be called during the constructor of