diff --git a/meson.build b/meson.build
index 88c3280c..416e55f8 100644
--- a/meson.build
+++ b/meson.build
@@ -101,6 +101,7 @@ vst3_plugin_sources = [
'src/common/utils.cpp',
'src/plugin/bridges/vst3.cpp',
'src/plugin/bridges/vst3-impls/plugin-factory.cpp',
+ 'src/plugin/bridges/vst3-impls/plug-view-proxy.cpp',
'src/plugin/bridges/vst3-impls/plugin-proxy.cpp',
'src/plugin/host-process.cpp',
'src/plugin/utils.cpp',
diff --git a/src/plugin/bridges/vst3-impls/plug-view-proxy.cpp b/src/plugin/bridges/vst3-impls/plug-view-proxy.cpp
new file mode 100644
index 00000000..0ab49fa0
--- /dev/null
+++ b/src/plugin/bridges/vst3-impls/plug-view-proxy.cpp
@@ -0,0 +1,122 @@
+// 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 "plug-view-proxy.h"
+
+Vst3PlugViewProxyImpl::Vst3PlugViewProxyImpl(
+ Vst3PluginBridge& bridge,
+ Vst3PlugViewProxy::ConstructArgs&& args)
+ : Vst3PlugViewProxy(std::move(args)), bridge(bridge) {}
+
+Vst3PlugViewProxyImpl::~Vst3PlugViewProxyImpl() {
+ // TODO: Implement this:
+ // // Also drop the plug view smart pointer on the Wine side when this gets
+ // // dropped
+ // bridge.send_message(
+ // Vst3PlugViewProxy::Destruct{.instance_id = instance_id()});
+}
+
+tresult PLUGIN_API
+Vst3PlugViewProxyImpl::queryInterface(const Steinberg::TUID _iid, void** obj) {
+ // TODO: Successful queries should also be logged
+ const tresult result = Vst3PlugViewProxy::queryInterface(_iid, obj);
+ if (result != Steinberg::kResultOk) {
+ bridge.logger.log_unknown_interface("In IPlugView::queryInterface()",
+ Steinberg::FUID::fromTUID(_iid));
+ }
+
+ return result;
+}
+
+tresult PLUGIN_API
+Vst3PlugViewProxyImpl::isPlatformTypeSupported(Steinberg::FIDString type) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::isPlatformTypeSupported()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::attached(void* parent,
+ Steinberg::FIDString type) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::attached()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::removed() {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::removed()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::onWheel(float distance) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::onWheel()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::onKeyDown(char16 key,
+ int16 keyCode,
+ int16 modifiers) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::onKeyDown()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::onKeyUp(char16 key,
+ int16 keyCode,
+ int16 modifiers) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::onKeyUp()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::getSize(Steinberg::ViewRect* size) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::getSize()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::onSize(Steinberg::ViewRect* newSize) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::onSize()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::onFocus(TBool state) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::onFocus()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API
+Vst3PlugViewProxyImpl::setFrame(Steinberg::IPlugFrame* frame) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::setFrame()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API Vst3PlugViewProxyImpl::canResize() {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::canResize()");
+ return Steinberg::kNotImplemented;
+}
+
+tresult PLUGIN_API
+Vst3PlugViewProxyImpl::checkSizeConstraint(Steinberg::ViewRect* rect) {
+ // TODO: Implement
+ bridge.logger.log("TODO: IPluginView::checkSizeConstraint()");
+ return Steinberg::kNotImplemented;
+}
diff --git a/src/plugin/bridges/vst3-impls/plug-view-proxy.h b/src/plugin/bridges/vst3-impls/plug-view-proxy.h
new file mode 100644
index 00000000..4e497621
--- /dev/null
+++ b/src/plugin/bridges/vst3-impls/plug-view-proxy.h
@@ -0,0 +1,62 @@
+// 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 "../vst3.h"
+
+class Vst3PlugViewProxyImpl : public Vst3PlugViewProxy {
+ public:
+ Vst3PlugViewProxyImpl(Vst3PluginBridge& bridge,
+ Vst3PlugViewProxy::ConstructArgs&& args);
+
+ /**
+ * When the reference count reaches zero and this destructor is called,
+ * we'll send a request to the Wine plugin host to destroy the corresponding
+ * object.
+ */
+ ~Vst3PlugViewProxyImpl();
+
+ /**
+ * We'll override the query interface to log queries for interfaces we do
+ * not (yet) support.
+ */
+ tresult PLUGIN_API queryInterface(const Steinberg::TUID _iid,
+ void** obj) override;
+
+ // From `IPlugView`
+ tresult PLUGIN_API
+ isPlatformTypeSupported(Steinberg::FIDString type) override;
+ tresult PLUGIN_API attached(void* parent,
+ Steinberg::FIDString type) override;
+ tresult PLUGIN_API removed() override;
+ tresult PLUGIN_API onWheel(float distance) override;
+ tresult PLUGIN_API onKeyDown(char16 key,
+ int16 keyCode,
+ int16 modifiers) override;
+ tresult PLUGIN_API onKeyUp(char16 key,
+ int16 keyCode,
+ int16 modifiers) override;
+ tresult PLUGIN_API getSize(Steinberg::ViewRect* size) override;
+ tresult PLUGIN_API onSize(Steinberg::ViewRect* newSize) override;
+ tresult PLUGIN_API onFocus(TBool state) override;
+ tresult PLUGIN_API setFrame(Steinberg::IPlugFrame* frame) override;
+ tresult PLUGIN_API canResize() override;
+ tresult PLUGIN_API checkSizeConstraint(Steinberg::ViewRect* rect) override;
+
+ private:
+ Vst3PluginBridge& bridge;
+};