From b794cdeafe955c9f9e6d4d05d141eaaf79275d82 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 5 Nov 2023 16:25:30 +0100 Subject: [PATCH] Rework ParentWindowHandle to be a sum type So we can mix and match versions of baseview that target different versions of `raw_window_handle`. --- CHANGELOG.md | 10 +++++++++ src/editor.rs | 34 +++++++++++++++++++++++++++---- src/wrapper/clap/wrapper.rs | 28 ++++++++++++------------- src/wrapper/standalone/wrapper.rs | 23 +++++++++++++++------ src/wrapper/vst3/view.rs | 29 ++++++++------------------ 5 files changed, 79 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5db398a7..aa4c1daa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,16 @@ state is to list breaking changes. may require small changes before they behave the same again. A summary of the most important changes can be found in Vizia PR [#291](https://github.com/vizia/vizia/pull/291). +- The `raw_window_handle` version used by NIH-plug has been updated to version + 0.5.x. + +### Changed + +- `ParentWindowHandle` has changed to be a sum type of different parent window + handle types, similar to `RawWindowHandle`. This makes it easier to use GUI + libraries that link against a different version of `raw_window_handle` than + the one used by NIH-plug itself by simply wrapping around + `ParentWindowHandle`. ## [2023-12-30] diff --git a/src/editor.rs b/src/editor.rs index 79c126f9..c6bd190e 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -2,6 +2,7 @@ use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; use std::any::Any; +use std::ffi::c_void; use std::sync::Arc; use crate::prelude::GuiContext; @@ -75,13 +76,38 @@ pub trait Editor: Send { // TODO: Host->Plugin resizing } -/// A raw window handle for platform and GUI framework agnostic editors. -pub struct ParentWindowHandle { - pub handle: RawWindowHandle, +/// A raw window handle for platform and GUI framework agnostic editors. This implements +/// [`HasRawWindowHandle`] so it can be used directly with GUI libraries that use the same +/// [`raw_window_handle`] version. If the library links against a different version of +/// `raw_window_handle`, then you'll need to wrap around this type and implement the trait yourself. +#[derive(Debug, Clone, Copy)] +pub enum ParentWindowHandle { + /// The ID of the host's parent window. Used with X11. + X11Window(u32), + /// A handle to the host's parent window. Used only on macOS. + AppKitNsView(*mut c_void), + /// A handle to the host's parent window. Used only on Windows. + Win32Hwnd(*mut c_void), } unsafe impl HasRawWindowHandle for ParentWindowHandle { fn raw_window_handle(&self) -> RawWindowHandle { - self.handle + match *self { + ParentWindowHandle::X11Window(window) => { + let mut handle = raw_window_handle::XcbWindowHandle::empty(); + handle.window = window; + RawWindowHandle::Xcb(handle) + } + ParentWindowHandle::AppKitNsView(ns_view) => { + let mut handle = raw_window_handle::AppKitWindowHandle::empty(); + handle.ns_view = ns_view; + RawWindowHandle::AppKit(handle) + } + ParentWindowHandle::Win32Hwnd(hwnd) => { + let mut handle = raw_window_handle::Win32WindowHandle::empty(); + handle.hwnd = hwnd; + RawWindowHandle::Win32(handle) + } + } } } diff --git a/src/wrapper/clap/wrapper.rs b/src/wrapper/clap/wrapper.rs index 81b56a64..690159e6 100644 --- a/src/wrapper/clap/wrapper.rs +++ b/src/wrapper/clap/wrapper.rs @@ -64,7 +64,6 @@ use crossbeam::atomic::AtomicCell; use crossbeam::channel::{self, SendTimeoutError}; use crossbeam::queue::ArrayQueue; use parking_lot::Mutex; -use raw_window_handle::RawWindowHandle; use std::any::Any; use std::borrow::Borrow; use std::collections::{HashMap, HashSet, VecDeque}; @@ -2769,28 +2768,27 @@ impl Wrapper

{ let mut editor_handle = wrapper.editor_handle.lock(); if editor_handle.is_none() { let api = CStr::from_ptr(window.api); - let handle = if api == CLAP_WINDOW_API_X11 { - let mut handle = raw_window_handle::XcbHandle::empty(); - handle.window = window.specific.x11 as u32; - RawWindowHandle::Xcb(handle) + let parent_handle = if api == CLAP_WINDOW_API_X11 { + ParentWindowHandle::X11Window(window.specific.x11 as u32) } else if api == CLAP_WINDOW_API_COCOA { - let mut handle = raw_window_handle::AppKitHandle::empty(); - handle.ns_view = window.specific.cocoa; - RawWindowHandle::AppKit(handle) + ParentWindowHandle::AppKitNsView(window.specific.cocoa) } else if api == CLAP_WINDOW_API_WIN32 { - let mut handle = raw_window_handle::Win32Handle::empty(); - handle.hwnd = window.specific.win32; - RawWindowHandle::Win32(handle) + ParentWindowHandle::AppKitNsView(window.specific.win32) } else { nih_debug_assert_failure!("Host passed an invalid API"); return false; }; // This extension is only exposed when we have an editor - *editor_handle = Some(wrapper.editor.borrow().as_ref().unwrap().lock().spawn( - ParentWindowHandle { handle }, - wrapper.clone().make_gui_context(), - )); + *editor_handle = Some( + wrapper + .editor + .borrow() + .as_ref() + .unwrap() + .lock() + .spawn(parent_handle, wrapper.clone().make_gui_context()), + ); true } else { diff --git a/src/wrapper/standalone/wrapper.rs b/src/wrapper/standalone/wrapper.rs index 5682b950..43476cc1 100644 --- a/src/wrapper/standalone/wrapper.rs +++ b/src/wrapper/standalone/wrapper.rs @@ -345,16 +345,27 @@ impl> Wrapper { gl_config: None, }, move |window| { + let parent_handle = match window.raw_window_handle() { + raw_window_handle::RawWindowHandle::Xlib(handle) => { + ParentWindowHandle::X11Window(handle.window as u32) + } + raw_window_handle::RawWindowHandle::Xcb(handle) => { + ParentWindowHandle::X11Window(handle.window) + } + raw_window_handle::RawWindowHandle::AppKit(handle) => { + ParentWindowHandle::AppKitNsView(handle.ns_view) + } + raw_window_handle::RawWindowHandle::Win32(handle) => { + ParentWindowHandle::Win32Hwnd(handle.hwnd) + } + handle => unimplemented!("Unsupported window handle: {handle:?}"), + }; + // TODO: This spawn function should be able to fail and return an error, but // baseview does not support this yet. Once this is added, we should // immediately close the parent window when this happens so the loop // can exit. - let editor_handle = editor.lock().spawn( - ParentWindowHandle { - handle: window.raw_window_handle(), - }, - context, - ); + let editor_handle = editor.lock().spawn(parent_handle, context); WrapperWindowHandler { _editor_handle: editor_handle, diff --git a/src/wrapper/vst3/view.rs b/src/wrapper/vst3/view.rs index 6f737ce3..051207e3 100644 --- a/src/wrapper/vst3/view.rs +++ b/src/wrapper/vst3/view.rs @@ -1,6 +1,5 @@ use atomic_float::AtomicF32; use parking_lot::{Mutex, RwLock}; -use raw_window_handle::RawWindowHandle; use std::any::Any; use std::ffi::{c_void, CStr}; use std::mem; @@ -290,35 +289,25 @@ impl IPlugView for WrapperView

{ let mut editor_handle = self.editor_handle.write(); if editor_handle.is_none() { let type_ = CStr::from_ptr(type_); - let handle = match type_.to_str() { - #[cfg(all(target_family = "unix", not(target_os = "macos")))] + let parent_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) + ParentWindowHandle::X11Window(parent as usize as u32) } - #[cfg(target_os = "macos")] Ok(type_) if type_ == VST3_PLATFORM_NSVIEW => { - let mut handle = raw_window_handle::AppKitHandle::empty(); - handle.ns_view = parent; - RawWindowHandle::AppKit(handle) - } - #[cfg(target_os = "windows")] - Ok(type_) if type_ == VST3_PLATFORM_HWND => { - let mut handle = raw_window_handle::Win32Handle::empty(); - handle.hwnd = parent; - RawWindowHandle::Win32(handle) + ParentWindowHandle::AppKitNsView(parent) } + Ok(type_) if type_ == VST3_PLATFORM_HWND => ParentWindowHandle::Win32Hwnd(parent), _ => { nih_debug_assert_failure!("Unknown window handle type: {:?}", type_); return kInvalidArgument; } }; - *editor_handle = Some(self.editor.lock().spawn( - ParentWindowHandle { handle }, - self.inner.clone().make_gui_context(), - )); + *editor_handle = Some( + self.editor + .lock() + .spawn(parent_handle, self.inner.clone().make_gui_context()), + ); *self.inner.plug_view.write() = Some(ObjectPtr::from(self)); kResultOk