From 7e240146b73c7ec56355cdf26cea76eca0fdd44a Mon Sep 17 00:00:00 2001
From: Robbert van der Helm <mail@robbertvanderhelm.nl>
Date: Sat, 5 Feb 2022 18:42:06 +0100
Subject: [PATCH] Implement IPlugView

---
 src/wrapper/vst3.rs | 160 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 133 insertions(+), 27 deletions(-)

diff --git a/src/wrapper/vst3.rs b/src/wrapper/vst3.rs
index 39b93b35..e0fe4294 100644
--- a/src/wrapper/vst3.rs
+++ b/src/wrapper/vst3.rs
@@ -24,7 +24,7 @@ use parking_lot::{RwLock, RwLockWriteGuard};
 use raw_window_handle::RawWindowHandle;
 use std::cmp;
 use std::collections::{HashMap, VecDeque};
-use std::ffi::c_void;
+use std::ffi::{c_void, CStr};
 use std::marker::PhantomData;
 use std::mem::{self, MaybeUninit};
 use std::ptr;
@@ -1284,62 +1284,168 @@ impl<P: Plugin> IAudioProcessor for Wrapper<P> {
 }
 
 impl<P: Plugin> IPlugView for WrapperView<P> {
-    unsafe fn is_platform_type_supported(&self, type_: vst3_com::base::FIDString) -> tresult {
-        todo!()
+    #[cfg(all(target_family = "unix", not(target_os = "macos")))]
+    unsafe fn is_platform_type_supported(&self, type_: vst3_sys::base::FIDString) -> tresult {
+        let type_ = CStr::from_ptr(type_);
+        match type_.to_str() {
+            Ok(type_) if type_ == VST3_PLATFORM_X11_WINDOW => kResultOk,
+            _ => {
+                nih_debug_assert_failure!("Invalid window handle type: {:?}", type_);
+                kResultFalse
+            }
+        }
     }
 
-    unsafe fn attached(&self, parent: *mut c_void, type_: vst3_com::base::FIDString) -> tresult {
-        todo!()
+    #[cfg(all(target_os = "macos"))]
+    unsafe fn is_platform_type_supported(&self, type_: vst3_sys::base::FIDString) -> tresult {
+        let type_ = CStr::from_ptr(type_);
+        match type_.to_str() {
+            Ok(type_) if type_ == VST3_PLATFORM_NSVIEW => kResultOk,
+            _ => {
+                nih_debug_assert_failure!("Invalid window handle type: {:?}", type_);
+                kResultFalse
+            }
+        }
+    }
+
+    #[cfg(all(target_os = "windows"))]
+    unsafe fn is_platform_type_supported(&self, type_: vst3_sys::base::FIDString) -> tresult {
+        let type_ = CStr::from_ptr(type_);
+        match type_.to_str() {
+            Ok(type_) if type_ == VST3_PLATFORM_HWND => kResultOk,
+            _ => {
+                nih_debug_assert_failure!("Invalid window handle type: {:?}", type_);
+                kResultFalse
+            }
+        }
+    }
+
+    unsafe fn attached(&self, parent: *mut c_void, type_: vst3_sys::base::FIDString) -> tresult {
+        let mut editor = self.editor.write();
+        if editor.is_none() {
+            let type_ = CStr::from_ptr(type_);
+            let handle = match type_.to_str() {
+                Ok(type_) if type_ == VST3_PLATFORM_X11_WINDOW => {
+                    let mut handle = raw_window_handle::XcbHandle::empty();
+                    handle.window = parent as usize as u32;
+                    RawWindowHandle::Xcb(handle)
+                }
+                Ok(type_) if type_ == VST3_PLATFORM_NSVIEW => {
+                    let mut handle = raw_window_handle::AppKitHandle::empty();
+                    handle.ns_view = parent;
+                    RawWindowHandle::AppKit(handle)
+                }
+                Ok(type_) if type_ == VST3_PLATFORM_HWND => {
+                    let mut handle = raw_window_handle::Win32Handle::empty();
+                    handle.hwnd = parent;
+                    RawWindowHandle::Win32(handle)
+                }
+                _ => {
+                    nih_debug_assert_failure!("Unknown window handle type: {:?}", type_);
+                    return kInvalidArgument;
+                }
+            };
+
+            *editor = self
+                .inner
+                .plugin
+                .write()
+                .create_editor(handle, self.inner.clone());
+            kResultOk
+        } else {
+            kResultFalse
+        }
     }
 
     unsafe fn removed(&self) -> tresult {
-        todo!()
+        let mut editor = self.editor.write();
+        if editor.is_some() {
+            *editor = None;
+            kResultOk
+        } else {
+            kResultFalse
+        }
     }
 
-    unsafe fn on_wheel(&self, distance: f32) -> tresult {
-        todo!()
+    unsafe fn on_wheel(&self, _distance: f32) -> tresult {
+        // We'll let the plugin use the OS' input mechamisms because not all DAWs (or very few
+        // actually) implement these functions
+        kResultOk
     }
 
     unsafe fn on_key_down(
         &self,
-        key: vst3_com::base::char16,
-        key_code: i16,
-        modifiers: i16,
+        _key: vst3_sys::base::char16,
+        _key_code: i16,
+        _modifiers: i16,
     ) -> tresult {
-        todo!()
+        kResultOk
     }
 
     unsafe fn on_key_up(
         &self,
-        key: vst3_com::base::char16,
-        key_code: i16,
-        modifiers: i16,
+        _key: vst3_sys::base::char16,
+        _key_code: i16,
+        _modifiers: i16,
     ) -> tresult {
-        todo!()
+        kResultOk
     }
 
-    unsafe fn get_size(&self, size: *mut vst3_com::gui::ViewRect) -> tresult {
-        todo!()
+    unsafe fn get_size(&self, size: *mut vst3_sys::gui::ViewRect) -> tresult {
+        check_null_ptr!(size);
+
+        // If the editor is already open, then take the size from the editor in case the plugin
+        // updates one but not the other
+        let (width, height) = match self.editor.read().as_ref() {
+            Some(editor) => editor.size(),
+            None => self
+                .inner
+                .plugin
+                .read()
+                .editor_size()
+                .expect("Wait, this returned a Some just now!?"),
+        };
+
+        *size = mem::zeroed();
+
+        let size = &mut *size;
+        size.left = 0;
+        size.right = width as i32;
+        size.top = 0;
+        size.bottom = height as i32;
+
+        kResultOk
     }
 
-    unsafe fn on_size(&self, new_size: *mut vst3_com::gui::ViewRect) -> tresult {
-        todo!()
+    unsafe fn on_size(&self, _new_size: *mut vst3_sys::gui::ViewRect) -> tresult {
+        // TODO: Implement resizing
+        kResultOk
     }
 
-    unsafe fn on_focus(&self, state: TBool) -> tresult {
-        todo!()
+    unsafe fn on_focus(&self, _state: TBool) -> tresult {
+        kResultOk
     }
 
-    unsafe fn set_frame(&self, frame: *mut c_void) -> tresult {
-        todo!()
+    unsafe fn set_frame(&self, _frame: *mut c_void) -> tresult {
+        // TODO: Implement resizing. We don't implement that right now, so we also don't need the
+        //       plug frame.
+        kResultOk
     }
 
     unsafe fn can_resize(&self) -> tresult {
-        todo!()
+        // TODO: Implement resizing
+        kResultFalse
     }
 
-    unsafe fn check_size_constraint(&self, rect: *mut vst3_com::gui::ViewRect) -> tresult {
-        todo!()
+    unsafe fn check_size_constraint(&self, rect: *mut vst3_sys::gui::ViewRect) -> tresult {
+        check_null_ptr!(rect);
+
+        // TODO: Add this with the resizing
+        if (*rect).right - (*rect).left > 0 && (*rect).bottom - (*rect).top > 0 {
+            kResultOk
+        } else {
+            kResultFalse
+        }
     }
 }