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;
};