1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

VST Host: Use a "wrapper" window on Linux so that the client does not have to be responsible for window position

Previously, on Linux, client plugin editors were embedded directly into the peer
displaying the client's AudioProcessorEditor.

Although this approach is simple and lightweight, it means that plugin
editors are able to reposition themselves over controls in the parent
window just by calling XMoveResizeWindow or similar on their own widget.

It's more desirable that the client editor should be clipped if it
attempts to draw outside the area of the AudioProcessorEditor.
This commit is contained in:
reuk 2025-10-28 17:56:53 +00:00
parent cad3e2f054
commit 983cbdc441
No known key found for this signature in database

View file

@ -42,8 +42,6 @@ namespace juce
#if JUCE_LINUX || JUCE_BSD
using EventProcPtr = void (*)(XEvent*);
static Window getChildWindow (Window windowToCheck)
{
Window rootWindow, parentWindow;
@ -106,6 +104,8 @@ public:
#if JUCE_WINDOWS
addAndMakeVisible (embeddedComponent);
#elif JUCE_LINUX || JUCE_BSD
addAndMakeVisible (xembedComponent);
#endif
}
@ -182,23 +182,7 @@ public:
void paint (Graphics& g) override
{
#if JUCE_LINUX || JUCE_BSD
if (isOpen)
{
if (pluginWindow != 0)
{
auto clip = componentToVstRect (*this, g.getClipBounds().toNearestInt());
X11Symbols::getInstance()->xClearArea (display, pluginWindow, clip.getX(), clip.getY(),
static_cast<unsigned int> (clip.getWidth()),
static_cast<unsigned int> (clip.getHeight()), True);
}
}
else
#endif
{
g.fillAll (Colours::black);
}
g.fillAll (Colours::black);
}
void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
@ -213,17 +197,11 @@ public:
#if JUCE_WINDOWS
embeddedComponent.setBounds (getLocalBounds());
#elif JUCE_LINUX || JUCE_BSD
const auto pos = componentToVstRect (*this, getLocalBounds());
xembedComponent.setBounds (getLocalBounds());
if (pluginWindow != 0)
{
auto* symbols = X11Symbols::getInstance();
symbols->xMoveResizeWindow (display,
pluginWindow,
pos.getX(),
pos.getY(),
(unsigned int) pos.getWidth(),
(unsigned int) pos.getHeight());
symbols->xMapRaised (display, pluginWindow);
symbols->xFlush (display);
}
@ -431,6 +409,8 @@ private:
#if JUCE_WINDOWS
auto* handle = embeddedComponent.getHWND();
#elif JUCE_LINUX || JUCE_BSD
auto* handle = desktopComponent.getPeer()->getNativeHandle();
#else
auto* handle = getWindowHandle();
#endif
@ -722,8 +702,33 @@ private:
void* originalWndProc = {};
int sizeCheckCount = 0;
#elif JUCE_LINUX || JUCE_BSD
// This is to provide a consistent X11 window handle with the same lifetime as the
// VSTPluginWindow. Using the VSTPluginWindow's peer directly would mean that the X11 window
// handle could change if the same VST window instance is repeatedly added/removed from the
// desktop.
// We then XEmbed this stable window into the VSTPluginFormat, and also use the stable window
// as the parent for the client VST window.
// We're not XEmbedding the client VST window directly, because it's not clear that VST
// hosts & clients expect to use the XEmbed protocol.
class DesktopComponent : public Component
{
public:
DesktopComponent()
{
setOpaque (true);
addToDesktop (0);
}
void paint (Graphics& g) override
{
g.fillAll (Colours::black);
}
};
::Display* display = XWindowSystem::getInstance()->getDisplay();
Window pluginWindow = 0;
DesktopComponent desktopComponent;
XEmbedComponent xembedComponent { reinterpret_cast<Window> (desktopComponent.getPeer()->getNativeHandle()), true, false };
#endif
#else
static constexpr auto nativeScaleFactor = 1.0f;