mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-14 00:14:18 +00:00
VST3: Added HWNDComponentWithParent class for Windows hosting and removed platform-specific IPlugViewContentScaleSupport implementation
This commit is contained in:
parent
cb57904740
commit
455e08da3f
2 changed files with 148 additions and 127 deletions
|
|
@ -31,10 +31,6 @@
|
||||||
namespace juce
|
namespace juce
|
||||||
{
|
{
|
||||||
|
|
||||||
#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE
|
|
||||||
extern void setThreadDPIAwarenessForWindow (HWND);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace Steinberg;
|
using namespace Steinberg;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
@ -1140,9 +1136,7 @@ private:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
struct VST3PluginWindow : public AudioProcessorEditor,
|
struct VST3PluginWindow : public AudioProcessorEditor,
|
||||||
public ComponentMovementWatcher,
|
public ComponentMovementWatcher,
|
||||||
#if JUCE_WINDOWS || JUCE_LINUX
|
|
||||||
public ComponentPeer::ScaleFactorListener,
|
public ComponentPeer::ScaleFactorListener,
|
||||||
#endif
|
|
||||||
public IPlugFrame
|
public IPlugFrame
|
||||||
{
|
{
|
||||||
VST3PluginWindow (AudioProcessor* owner, IPlugView* pluginView)
|
VST3PluginWindow (AudioProcessor* owner, IPlugView* pluginView)
|
||||||
|
|
@ -1155,26 +1149,20 @@ struct VST3PluginWindow : public AudioProcessorEditor,
|
||||||
setVisible (true);
|
setVisible (true);
|
||||||
|
|
||||||
warnOnFailure (view->setFrame (this));
|
warnOnFailure (view->setFrame (this));
|
||||||
|
|
||||||
#if ! JUCE_MAC
|
|
||||||
view->queryInterface (Steinberg::IPlugViewContentScaleSupport::iid, (void**) &scaleInterface);
|
view->queryInterface (Steinberg::IPlugViewContentScaleSupport::iid, (void**) &scaleInterface);
|
||||||
#endif
|
|
||||||
|
|
||||||
resizeToFit();
|
resizeToFit();
|
||||||
}
|
}
|
||||||
|
|
||||||
~VST3PluginWindow() override
|
~VST3PluginWindow() override
|
||||||
{
|
{
|
||||||
#if ! JUCE_MAC
|
|
||||||
if (scaleInterface != nullptr)
|
if (scaleInterface != nullptr)
|
||||||
scaleInterface->release();
|
scaleInterface->release();
|
||||||
|
|
||||||
removeScaleFactorListeners();
|
removeScaleFactorListener();
|
||||||
|
|
||||||
#if JUCE_LINUX
|
#if JUCE_LINUX
|
||||||
embeddedComponent.removeClient();
|
embeddedComponent.removeClient();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
warnOnFailure (view->removed());
|
warnOnFailure (view->removed());
|
||||||
warnOnFailure (view->setFrame (nullptr));
|
warnOnFailure (view->setFrame (nullptr));
|
||||||
|
|
@ -1183,6 +1171,8 @@ struct VST3PluginWindow : public AudioProcessorEditor,
|
||||||
|
|
||||||
#if JUCE_MAC
|
#if JUCE_MAC
|
||||||
embeddedComponent.setView (nullptr);
|
embeddedComponent.setView (nullptr);
|
||||||
|
#elif JUCE_WINDOWS
|
||||||
|
embeddedComponent.setHWND (nullptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
view = nullptr;
|
view = nullptr;
|
||||||
|
|
@ -1323,79 +1313,50 @@ struct VST3PluginWindow : public AudioProcessorEditor,
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void componentPeerChanged() override
|
void componentPeerChanged() override
|
||||||
{
|
{
|
||||||
#if ! JUCE_MAC
|
removeScaleFactorListener();
|
||||||
removeScaleFactorListeners();
|
currentPeer = getTopLevelComponent()->getPeer();
|
||||||
|
|
||||||
if (auto* topPeer = getTopLevelComponent()->getPeer())
|
if (currentPeer != nullptr)
|
||||||
topPeer->addScaleFactorListener (this);
|
{
|
||||||
#endif
|
currentPeer->addScaleFactorListener (this);
|
||||||
|
nativeScaleFactor = (float) currentPeer->getPlatformScaleFactor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void componentMovedOrResized (bool, bool wasResized) override
|
void componentMovedOrResized (bool, bool wasResized) override
|
||||||
{
|
{
|
||||||
if (recursiveResize)
|
if (recursiveResize || ! wasResized || getTopLevelComponent()->getPeer() == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto* topComp = getTopLevelComponent();
|
ViewRect rect;
|
||||||
|
|
||||||
if (topComp->getPeer() != nullptr)
|
if (view->canResize() == kResultTrue)
|
||||||
{
|
{
|
||||||
#if JUCE_WINDOWS
|
rect.right = (Steinberg::int32) roundToInt ((float) getWidth() * nativeScaleFactor);
|
||||||
auto pos = (topComp->getLocalPoint (this, Point<int>()) * nativeScaleFactor).roundToInt();
|
rect.bottom = (Steinberg::int32) roundToInt ((float) getHeight() * nativeScaleFactor);
|
||||||
#endif
|
|
||||||
|
|
||||||
const ScopedValueSetter<bool> recursiveResizeSetter (recursiveResize, true);
|
view->checkSizeConstraint (&rect);
|
||||||
|
|
||||||
ViewRect rect;
|
|
||||||
|
|
||||||
if (wasResized && view->canResize() == kResultTrue)
|
|
||||||
{
|
{
|
||||||
rect.right = (Steinberg::int32) roundToInt ((float) getWidth() * nativeScaleFactor);
|
const ScopedValueSetter<bool> recursiveResizeSetter (recursiveResize, true);
|
||||||
rect.bottom = (Steinberg::int32) roundToInt ((float) getHeight() * nativeScaleFactor);
|
|
||||||
|
|
||||||
view->checkSizeConstraint (&rect);
|
setSize (roundToInt ((float) rect.getWidth() / nativeScaleFactor),
|
||||||
|
roundToInt ((float) rect.getHeight() / nativeScaleFactor));
|
||||||
auto w = roundToInt ((float) rect.getWidth() / nativeScaleFactor);
|
|
||||||
auto h = roundToInt ((float) rect.getHeight() / nativeScaleFactor);
|
|
||||||
|
|
||||||
setSize (w, h);
|
|
||||||
|
|
||||||
#if JUCE_WINDOWS
|
|
||||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
|
||||||
setThreadDPIAwarenessForWindow (pluginHandle);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SetWindowPos (pluginHandle, 0,
|
|
||||||
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
|
|
||||||
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
|
|
||||||
#else
|
|
||||||
embeddedComponent.setBounds (getLocalBounds());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
view->onSize (&rect);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
warnOnFailure (view->getSize (&rect));
|
|
||||||
|
|
||||||
#if JUCE_WINDOWS
|
|
||||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
|
||||||
setThreadDPIAwarenessForWindow (pluginHandle);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SetWindowPos (pluginHandle, 0,
|
|
||||||
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
|
|
||||||
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
|
|
||||||
#else
|
|
||||||
embeddedComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some plugins don't update their cursor correctly when mousing out the window
|
embeddedComponent.setBounds (getLocalBounds());
|
||||||
Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
|
|
||||||
|
view->onSize (&rect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warnOnFailure (view->getSize (&rect));
|
||||||
|
resizeWithRect (embeddedComponent, rect, nativeScaleFactor);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// Some plugins don't update their cursor correctly when mousing out the window
|
||||||
|
Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
|
||||||
|
}
|
||||||
using ComponentMovementWatcher::componentMovedOrResized;
|
using ComponentMovementWatcher::componentMovedOrResized;
|
||||||
|
|
||||||
void componentVisibilityChanged() override
|
void componentVisibilityChanged() override
|
||||||
|
|
@ -1407,13 +1368,11 @@ struct VST3PluginWindow : public AudioProcessorEditor,
|
||||||
|
|
||||||
componentMovedOrResized (true, true);
|
componentMovedOrResized (true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
using ComponentMovementWatcher::componentVisibilityChanged;
|
using ComponentMovementWatcher::componentVisibilityChanged;
|
||||||
|
|
||||||
#if JUCE_WINDOWS || JUCE_LINUX
|
|
||||||
void nativeScaleFactorChanged (double newScaleFactor) override
|
void nativeScaleFactorChanged (double newScaleFactor) override
|
||||||
{
|
{
|
||||||
if (pluginHandle == 0 || approximatelyEqual ((float) newScaleFactor, nativeScaleFactor))
|
if (pluginHandle == HandleFormat{} || approximatelyEqual ((float) newScaleFactor, nativeScaleFactor))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nativeScaleFactor = (float) newScaleFactor;
|
nativeScaleFactor = (float) newScaleFactor;
|
||||||
|
|
@ -1421,7 +1380,6 @@ struct VST3PluginWindow : public AudioProcessorEditor,
|
||||||
if (scaleInterface != nullptr)
|
if (scaleInterface != nullptr)
|
||||||
scaleInterface->setContentScaleFactor ((Steinberg::IPlugViewContentScaleSupport::ScaleFactor) nativeScaleFactor);
|
scaleInterface->setContentScaleFactor ((Steinberg::IPlugViewContentScaleSupport::ScaleFactor) nativeScaleFactor);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void resizeToFit()
|
void resizeToFit()
|
||||||
{
|
{
|
||||||
|
|
@ -1458,73 +1416,48 @@ private:
|
||||||
|
|
||||||
void attachPluginWindow()
|
void attachPluginWindow()
|
||||||
{
|
{
|
||||||
#if JUCE_MAC
|
if (pluginHandle == HandleFormat{})
|
||||||
if (pluginHandle == nil)
|
|
||||||
#else
|
|
||||||
if (pluginHandle == 0)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
#if JUCE_WINDOWS
|
|
||||||
if (auto* topComp = getTopLevelComponent())
|
|
||||||
{
|
|
||||||
peer.reset (embeddedComponent.createNewPeer (0, topComp->getWindowHandle()));
|
|
||||||
pluginHandle = (HandleFormat) peer->getNativeHandle();
|
|
||||||
nativeScaleFactor = (float) peer->getPlatformScaleFactor();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
embeddedComponent.setBounds (getLocalBounds());
|
embeddedComponent.setBounds (getLocalBounds());
|
||||||
addAndMakeVisible (embeddedComponent);
|
addAndMakeVisible (embeddedComponent);
|
||||||
#if JUCE_MAC
|
|
||||||
pluginHandle = (HandleFormat) embeddedComponent.getView();
|
|
||||||
jassert (pluginHandle != nil);
|
|
||||||
#elif JUCE_LINUX
|
|
||||||
pluginHandle = (HandleFormat) embeddedComponent.getHostWindowID();
|
|
||||||
jassert (pluginHandle != 0);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if JUCE_MAC
|
#if JUCE_MAC
|
||||||
if (pluginHandle != nil)
|
pluginHandle = (HandleFormat) embeddedComponent.getView();
|
||||||
#else
|
#elif JUCE_WINDOWS
|
||||||
if (pluginHandle != 0)
|
pluginHandle = (HandleFormat) embeddedComponent.getHWND();
|
||||||
|
#elif JUCE_LINUX
|
||||||
|
pluginHandle = (HandleFormat) embeddedComponent.getHostWindowID();
|
||||||
#endif
|
#endif
|
||||||
warnOnFailure (view->attached ((void*) pluginHandle, defaultVST3WindowType));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ! JUCE_MAC
|
if (pluginHandle == HandleFormat{})
|
||||||
if (auto* topPeer = getTopLevelComponent()->getPeer())
|
{
|
||||||
{
|
jassertfalse;
|
||||||
nativeScaleFactor = 1.0f; // force update
|
return;
|
||||||
nativeScaleFactorChanged ((float) topPeer->getPlatformScaleFactor());
|
}
|
||||||
|
|
||||||
|
warnOnFailure (view->attached ((void*) pluginHandle, defaultVST3WindowType));
|
||||||
|
|
||||||
|
if (scaleInterface != nullptr)
|
||||||
|
scaleInterface->setContentScaleFactor ((Steinberg::IPlugViewContentScaleSupport::ScaleFactor) nativeScaleFactor);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ! JUCE_MAC
|
void removeScaleFactorListener()
|
||||||
void removeScaleFactorListeners()
|
|
||||||
{
|
{
|
||||||
|
if (currentPeer == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < ComponentPeer::getNumPeers(); ++i)
|
for (int i = 0; i < ComponentPeer::getNumPeers(); ++i)
|
||||||
if (auto* p = ComponentPeer::getPeer (i))
|
if (ComponentPeer::getPeer (i) == currentPeer)
|
||||||
p->removeScaleFactorListener (this);
|
currentPeer->removeScaleFactorListener (this);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
Atomic<int> refCount { 1 };
|
Atomic<int> refCount { 1 };
|
||||||
VSTComSmartPtr<IPlugView> view;
|
VSTComSmartPtr<IPlugView> view;
|
||||||
|
|
||||||
#if JUCE_WINDOWS
|
#if JUCE_WINDOWS
|
||||||
struct ChildComponent : public Component
|
HWNDComponentWithParent embeddedComponent;
|
||||||
{
|
|
||||||
ChildComponent() {}
|
|
||||||
void paint (Graphics& g) override { g.fillAll (Colours::cornflowerblue); }
|
|
||||||
using Component::createNewPeer;
|
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildComponent)
|
|
||||||
};
|
|
||||||
|
|
||||||
ChildComponent embeddedComponent;
|
|
||||||
std::unique_ptr<ComponentPeer> peer;
|
|
||||||
using HandleFormat = HWND;
|
using HandleFormat = HWND;
|
||||||
#elif JUCE_MAC
|
#elif JUCE_MAC
|
||||||
AutoResizingNSViewComponentWithParent embeddedComponent;
|
AutoResizingNSViewComponentWithParent embeddedComponent;
|
||||||
|
|
@ -1538,14 +1471,11 @@ private:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HandleFormat pluginHandle = {};
|
HandleFormat pluginHandle = {};
|
||||||
bool recursiveResize = false;
|
bool recursiveResize = false, hasDoneInitialResize = false;
|
||||||
|
|
||||||
#if ! JUCE_MAC
|
ComponentPeer* currentPeer = nullptr;
|
||||||
Steinberg::IPlugViewContentScaleSupport* scaleInterface = nullptr;
|
Steinberg::IPlugViewContentScaleSupport* scaleInterface = nullptr;
|
||||||
#endif
|
|
||||||
|
|
||||||
float nativeScaleFactor = 1.0f;
|
float nativeScaleFactor = 1.0f;
|
||||||
bool hasDoneInitialResize = false;
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3PluginWindow)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VST3PluginWindow)
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,97 @@ static bool arrayContainsPlugin (const OwnedArray<PluginDescription>& list,
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if JUCE_MAC || JUCE_IOS
|
#if JUCE_WINDOWS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class HWNDComponentWithParent : public HWNDComponent,
|
||||||
|
private Timer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HWNDComponentWithParent()
|
||||||
|
{
|
||||||
|
String className ("JUCE_");
|
||||||
|
className << String::toHexString (Time::getHighResolutionTicks());
|
||||||
|
|
||||||
|
HMODULE moduleHandle = (HMODULE) Process::getCurrentModuleInstanceHandle();
|
||||||
|
|
||||||
|
WNDCLASSEX wc = {};
|
||||||
|
wc.cbSize = sizeof (wc);
|
||||||
|
wc.lpfnWndProc = (WNDPROC) wndProc;
|
||||||
|
wc.cbWndExtra = 4;
|
||||||
|
wc.hInstance = moduleHandle;
|
||||||
|
wc.lpszClassName = className.toWideCharPointer();
|
||||||
|
|
||||||
|
atom = RegisterClassEx (&wc);
|
||||||
|
jassert (atom != 0);
|
||||||
|
|
||||||
|
hwnd = CreateWindow (getClassNameFromAtom(), L"HWNDComponentWithParent",
|
||||||
|
0, 0, 0, 0, 0,
|
||||||
|
nullptr, nullptr, moduleHandle, nullptr);
|
||||||
|
|
||||||
|
jassert (hwnd != nullptr);
|
||||||
|
|
||||||
|
setHWND (hwnd);
|
||||||
|
startTimer (30);
|
||||||
|
}
|
||||||
|
|
||||||
|
~HWNDComponentWithParent() override
|
||||||
|
{
|
||||||
|
if (IsWindow (hwnd))
|
||||||
|
DestroyWindow (hwnd);
|
||||||
|
|
||||||
|
UnregisterClass (getClassNameFromAtom(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
static LRESULT CALLBACK wndProc (HWND h, const UINT message, const WPARAM wParam, const LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (message == WM_SHOWWINDOW && wParam == TRUE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return DefWindowProc (h, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timerCallback() override
|
||||||
|
{
|
||||||
|
if (HWND child = getChildHWND())
|
||||||
|
{
|
||||||
|
stopTimer();
|
||||||
|
|
||||||
|
ShowWindow (child, SW_HIDE);
|
||||||
|
SetParent (child, NULL);
|
||||||
|
|
||||||
|
auto windowFlags = GetWindowLongPtr (child, -16);
|
||||||
|
|
||||||
|
windowFlags &= ~WS_CHILD;
|
||||||
|
windowFlags |= WS_POPUP;
|
||||||
|
|
||||||
|
SetWindowLongPtr (child, -16, windowFlags);
|
||||||
|
|
||||||
|
setHWND (child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LPCTSTR getClassNameFromAtom() noexcept { return (LPCTSTR) (pointer_sized_uint) atom; }
|
||||||
|
|
||||||
|
HWND getChildHWND() const
|
||||||
|
{
|
||||||
|
if (HWND parent = (HWND) getHWND())
|
||||||
|
return GetWindow (parent, GW_CHILD);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
ATOM atom;
|
||||||
|
HWND hwnd;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HWNDComponentWithParent)
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif JUCE_MAC || JUCE_IOS
|
||||||
|
|
||||||
#if JUCE_IOS
|
#if JUCE_IOS
|
||||||
#define JUCE_IOS_MAC_VIEW UIView
|
#define JUCE_IOS_MAC_VIEW UIView
|
||||||
|
|
@ -130,6 +220,7 @@ struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewCompone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace juce
|
} // namespace juce
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue