Inhibit the event loop during VST3 editor init

This should in theory prevent Nimble Kick from triggering a stack
overflow when the event loop timer procs before `IPlugView::attached()`
gets called and the plugin hasn't been registered yet. I haven't seen
any other VST3 plugins trigger a race condition here.
This commit is contained in:
Robbert van der Helm
2021-07-20 16:22:27 +02:00
parent 640c188338
commit ff76e482f2
2 changed files with 29 additions and 10 deletions
+2
View File
@@ -35,6 +35,8 @@ Versioning](https://semver.org/spec/v2.0.0.html).
like FrozenPlain **Obelisk** would result in a crash.
- Fixed a regression from yabridge 3.4.0 where JUCE-based VST3 plugins might
cause **Ardour** or **Mixbus** to freeze in very specific circumstances.
- Worked around a race condition in _Nimble Kick_, which would trigger a stack
overflow when loading the plugin if it wasn't already activated.
- When the window manager somehow steals yabridge's window away from the host,
yabridge will now try to steal it back and reparent it to the host's window
again. This very rarely happened with some window managers, like XFWM, and
+27 -10
View File
@@ -499,6 +499,16 @@ void Vst3Bridge::run() {
if (plug_view) {
instance.plug_view_instance.emplace(plug_view);
// HACK: Nimble Kick (and perhaps other plugins, but
// I haven't heard any reports of this being
// an issue coming from other plugins) starts
// a timer in `IEditController::createView()`
// that relies on data that is only
// initialized once `IPlugView::attached()`
// has been called. So until that point, we'll
// prevent the event loop from running.
instance.is_initialized = false;
} else {
instance.plug_view_instance.reset();
}
@@ -716,6 +726,9 @@ void Vst3Bridge::run() {
},
[&](const YaPlugView::Attached& request)
-> YaPlugView::Attached::Response {
Vst3PluginInstance& instance =
object_instances.at(request.owner_instance_id);
const std::string type =
request.type == Steinberg::kPlatformTypeX11EmbedWindowID
? Steinberg::kPlatformTypeHWND
@@ -729,23 +742,27 @@ void Vst3Bridge::run() {
// be done in the main UI thread
return main_context
.run_in_context([&]() -> tresult {
Editor& editor_instance =
object_instances.at(request.owner_instance_id)
.editor.emplace(main_context, config,
generic_logger, x11_handle);
Editor& editor_instance = instance.editor.emplace(
main_context, config, generic_logger, x11_handle);
const tresult result =
object_instances.at(request.owner_instance_id)
.plug_view_instance->plug_view->attached(
editor_instance.get_win32_handle(),
type.c_str());
instance.plug_view_instance->plug_view->attached(
editor_instance.get_win32_handle(),
type.c_str());
// Get rid of the editor again if the plugin didn't
// embed itself in it
if (result != Steinberg::kResultOk) {
object_instances.at(request.owner_instance_id)
.editor.reset();
instance.editor.reset();
}
// HACK: See the comment in our handling of
// `IEditController::createView()`. We'll reset
// this regardless of whether or not this request
// succeeded or else JUCE plugins without editors
// might cause us to get stuck in a situation
// where the event loop gets blocked indefinitely.
instance.is_initialized = true;
return result;
})
.get();