Always run the event loop, fixing processing issue

Also remove any special `effEditIdle` handling.

Apparently plugins rely on the message loop for their internal tasks,
even for things that have nothing to do with GUIs, such as deferring
initialization.
This commit is contained in:
Robbert van der Helm
2020-04-27 18:45:20 +02:00
parent e69d08c503
commit 4b84f663ab
4 changed files with 29 additions and 21 deletions
-2
View File
@@ -12,8 +12,6 @@ There are a few things that should be done before releasing this, including:
- Fix implementation bugs:
- Serum crashed and audio engine froze while browsing through Serum presets in
the browser?
- Plugins from certain manufacturers, such as KiloHearts or Image-Line, don't
do any audio processing until the editor has been opened.
- KiloHearts plugins create a ridiculous amount of file descriptor leaks in
wineserver when esync is enabled. I haven't come across any other plugins
that do this. Not sure if this is fixable in yabridge.
+7 -6
View File
@@ -131,18 +131,18 @@ void Editor::send_idle_event() {
}
void Editor::handle_events() {
send_idle_event();
MSG msg;
// The null value for the second argument is needed to handle interaction
// with child GUI components
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
// This timer would periodically send `effEditIdle` events so the editor
// remains responsive even during blocking GUI operations such as open
// dropdowns or message boxes. We filter it out here because we will
// send sent the event manually every time the host calls
// `effEditIdle()`. It will still be fired implicitely when the GUI
// thread gets blocked.
// dropdowns or message boxes. This is only needed when the GUI is
// actually blocked and it will be dispatched by the messaging loop of
// the blocking GUI component. Since we're not touching the
// `effEditIdle` event sent by the host we can always filter this timer
// event out in this event loop.
if (msg.message == WM_TIMER && msg.wParam == idle_timer_id &&
msg.hwnd == win32_handle.get()) {
continue;
@@ -201,6 +201,7 @@ void Editor::handle_events() {
xcb_flush(x11_connection.get());
} break;
}
free(generic_event);
}
}
+2 -2
View File
@@ -88,14 +88,14 @@ class Editor {
/**
* Send a single `effEditIdle` event to the plugin to allow it to update its
* GUI state. This is called periodically from a timer while the GUI is
* being blocked.
* being blocked, and also called explicitly by the host on a timer.
*/
void send_idle_event();
/**
* Pump messages from the editor GUI's event loop until all events are
* process. Must be run from the same thread the GUI was created in because
* of Win32 limitations. I guess that's what `effEditIdle` is for.
* of Win32 limitations.
*/
void handle_events();
+20 -11
View File
@@ -150,6 +150,26 @@ void PluginBridge::handle_dispatch() {
passthrough_event(host_vst_dispatch, std::nullopt, plugin,
std::bind(&PluginBridge::dispatch_wrapper, this,
_1, _2, _3, _4, _5, _6));
// Because of the way the Win32 API works we have to process events
// on the same thread as the one the window was created on, and that
// thread is the thread that's handling dispatcher calls.
if (editor.has_value()) {
// This will handle Win32 events similar to the loop below, and
// it will also handle any X11 events.
editor->handle_events();
} else {
MSG msg;
// Since some plugins rely on the Win32 message API even for
// non-editor related tasks (such as deferring the loading of
// presets using a timer), we have to run a message loop even
// when the editor is closed.
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
} catch (const boost::system::system_error&) {
// The plugin has cut off communications, so we can shut down this host
@@ -286,17 +306,6 @@ intptr_t PluginBridge::dispatch_wrapper(AEffect* plugin,
// We have to intercept GUI open calls since we can't use
// the X11 window handle passed by the host
switch (opcode) {
case effEditIdle:
// Because of the way the Win32 API works we have to process events
// on the same thread the window was created, and that thread is the
// thread that's handling dispatcher calls
// To allow the GUI to update even when this thread gets blocked
// (e.g. when a dropdown is open), the actual `effEditIdle` event
// gets sent to the plugin on a timer.
editor->handle_events();
return 1;
break;
case effEditOpen: {
// Create a Win32 window through Wine, embed it into the window
// provided by the host, and let the plugin embed itself into the