diff --git a/meson.build b/meson.build index 118d3d69..3e67f555 100644 --- a/meson.build +++ b/meson.build @@ -238,6 +238,7 @@ host_sources = [ 'src/common/logging/vst2.cpp', 'src/common/plugins.cpp', 'src/common/utils.cpp', + 'src/wine-host/bridges/common.cpp', 'src/wine-host/bridges/vst2.cpp', 'src/wine-host/editor.cpp', 'src/wine-host/editor.cpp', diff --git a/src/wine-host/bridges/common.cpp b/src/wine-host/bridges/common.cpp new file mode 100644 index 00000000..81bec63e --- /dev/null +++ b/src/wine-host/bridges/common.cpp @@ -0,0 +1,38 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "common.h" + +void HostBridge::handle_win32_events() { + if (editor) { + editor->handle_win32_events(); + } else { + MSG msg; + + for (int i = 0; i < max_win32_messages && + PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE); + i++) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +} + +void HostBridge::handle_x11_events() { + if (editor) { + editor->handle_x11_events(); + } +} diff --git a/src/wine-host/bridges/common.h b/src/wine-host/bridges/common.h new file mode 100644 index 00000000..d932ac50 --- /dev/null +++ b/src/wine-host/bridges/common.h @@ -0,0 +1,61 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "../editor.h" + +/** + * The base for the Wine plugin host bridge interface for all plugin types. This + * only has to be able to handle Win32 and X11 events. Implementations of this + * will actually host a plugin and do all the function call forwarding. + */ +class HostBridge { + public: + /** + * Handle X11 events for the editor window if it is open. This can safely be + * run from any thread. + */ + void handle_x11_events(); + + /** + * Run the message loop for this plugin. This is only used for the + * individual plugin host, so that we can filter out some unnecessary timer + * events. When hosting multiple plugins, a simple central message loop + * should be used instead. This is run on a timer in the same IO context as + * the one that handles the events, i.e. `main_context`. + * + * 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. Some plugins will also rely on + * the Win32 message loop to run tasks on a timer and to defer loading, so + * we have to make sure to always run this loop. The only exception is a in + * specific situation that can cause a race condition in some plugins + * because of incorrect assumptions made by the plugin. See the dostring for + * `HostBridge::editor` for more information. + */ + void handle_win32_events(); + + protected: + /** + * The plugin editor window. Allows embedding the plugin's editor into a + * Wine window, and embedding that Wine window into a window provided by the + * host. Should be empty when the editor is not open. + * + * @see should_postpone_message_loop + */ + std::optional editor; +}; diff --git a/src/wine-host/bridges/vst2.cpp b/src/wine-host/bridges/vst2.cpp index a52cdb8f..216d7e02 100644 --- a/src/wine-host/bridges/vst2.cpp +++ b/src/wine-host/bridges/vst2.cpp @@ -392,27 +392,6 @@ intptr_t Vst2Bridge::dispatch_wrapper(AEffect* plugin, } } -void Vst2Bridge::handle_win32_events() { - if (editor) { - editor->handle_win32_events(); - } else { - MSG msg; - - for (int i = 0; i < max_win32_messages && - PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE); - i++) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } -} - -void Vst2Bridge::handle_x11_events() { - if (editor) { - editor->handle_x11_events(); - } -} - class HostCallbackDataConverter : DefaultDataConverter { public: HostCallbackDataConverter(AEffect* plugin, diff --git a/src/wine-host/bridges/vst2.h b/src/wine-host/bridges/vst2.h index 070357b3..5d82c146 100644 --- a/src/wine-host/bridges/vst2.h +++ b/src/wine-host/bridges/vst2.h @@ -31,22 +31,14 @@ #include "../../common/communication/vst2.h" #include "../../common/configuration.h" -#include "../editor.h" #include "../utils.h" +#include "common.h" /** * This hosts a Windows VST2 plugin, forwards messages sent by the Linux VST * plugin and provides host callback function for the plugin to talk back. - * - * @remark Because of Win32 API limitations, all window handling has to be done - * from a single thread. Most plugins won't have any issues when using - * multiple message loops, but the Melda plugins for instance will only update - * their GUIs from the message loop of the thread that created the first - * instance. This is why we pass an IO context to this class so everything - * that's not performance critical (audio and midi event handling) is handled - * on the same thread, even when hosting multiple plugins. */ -class Vst2Bridge { +class Vst2Bridge : public HostBridge { public: /** * Initializes the Windows VST plugin and set up communication with the @@ -83,30 +75,6 @@ class Vst2Bridge { */ void handle_dispatch(); - /** - * Handle X11 events for the editor window if it is open. This can safely be - * run from any thread. - */ - void handle_x11_events(); - - /** - * Run the message loop for this plugin. This is only used for the - * individual plugin host, so that we can filter out some unnecessary timer - * events. When hosting multiple plugins, a simple central message loop - * should be used instead. This is run on a timer in the same IO context as - * the one that handles the events, i.e. `main_context`. - * - * 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. Some plugins will also rely on - * the Win32 message loop to run tasks on a timer and to defer loading, so - * we have to make sure to always run this loop. The only exception is a in - * specific situation that can cause a race condition in some plugins - * because of incorrect assumptions made by the plugin. See the dostring for - * `Vst2Bridge::editor` for more information. - */ - void handle_win32_events(); - /** * Forward the host callback made by the plugin to the host and return the * results. @@ -203,13 +171,4 @@ class Vst2Bridge { * now happens in two different threads. */ std::mutex next_buffer_midi_events_mutex; - - /** - * The plugin editor window. Allows embedding the plugin's editor into a - * Wine window, and embedding that Wine window into a window provided by the - * host. Should be empty when the editor is not open. - * - * @see should_postpone_message_loop - */ - std::optional editor; };