mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 03:50:11 +02:00
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:
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user