From fde2512f64e4fd6154491f6073b52f1bacb1fc0e Mon Sep 17 00:00:00 2001 From: attila Date: Thu, 8 Jan 2026 00:02:50 +0100 Subject: [PATCH] XEmbedComponent: Add new constructor taking XEmbedComponentOptions --- .../format_types/juce_VST3PluginFormat.cpp | 3 +- .../format_types/juce_VSTPluginFormat.cpp | 4 +- .../embedding/juce_XEmbedComponent.h | 57 +++++++++++++++++++ .../native/juce_XEmbedComponent_linux.cpp | 47 ++++++++------- 4 files changed, 88 insertions(+), 23 deletions(-) diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index cede28f25c..6aa6e50016 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -563,7 +563,8 @@ private: NSViewComponentWithParent embeddedComponent; using HandleFormat = NSView*; #elif JUCE_LINUX || JUCE_BSD - XEmbedComponent embeddedComponent { true, false }; + XEmbedComponent embeddedComponent { XEmbedComponentOptions{}.withWantsKeyboardFocus (true) + .withAllowForeignWidgetToResizeComponent (false) }; using HandleFormat = Window; #else Component embeddedComponent; diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index cc655a52fb..86a1286c75 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -728,7 +728,9 @@ private: ::Display* display = XWindowSystem::getInstance()->getDisplay(); Window pluginWindow = 0; DesktopComponent desktopComponent; - XEmbedComponent xembedComponent { reinterpret_cast (desktopComponent.getPeer()->getNativeHandle()), true, false }; + XEmbedComponent xembedComponent { XEmbedComponentOptions{}.withClientWindow (reinterpret_cast (desktopComponent.getPeer()->getNativeHandle())) + .withWantsKeyboardFocus (true) + .withAllowForeignWidgetToResizeComponent (false) }; #endif #else static constexpr auto nativeScaleFactor = 1.0f; diff --git a/modules/juce_gui_extra/embedding/juce_XEmbedComponent.h b/modules/juce_gui_extra/embedding/juce_XEmbedComponent.h index 1bce69dec8..d925d73fc4 100644 --- a/modules/juce_gui_extra/embedding/juce_XEmbedComponent.h +++ b/modules/juce_gui_extra/embedding/juce_XEmbedComponent.h @@ -42,6 +42,57 @@ unsigned long juce_getCurrentFocusWindow (ComponentPeer*); #if JUCE_LINUX || JUCE_BSD || DOXYGEN +/** Options for constructing an XEmbedComponent. + + @see XEmbedComponent +*/ +class JUCE_API XEmbedComponentOptions +{ +public: + /** Returns a copy of these options with the client window id specified. This corresponds to + the client initiated embedding workflow. + + Omitting this option corresponds to the host initiated embedding workflow. + */ + [[nodiscard]] XEmbedComponentOptions withClientWindow (unsigned long x) const + { + jassert (x != 0); + return withMember (*this, &XEmbedComponentOptions::clientWindow, x); + } + + /** Specifies that this Component wants to receive and forward keyboard focus. + + The default value is true. + */ + [[nodiscard]] XEmbedComponentOptions withWantsKeyboardFocus (bool x) const + { + return withMember (*this, &XEmbedComponentOptions::wantsKeyboardFocus, x); + } + + /** Specifies that the embedded window is allowed to resize the Component. + + The default value is false. + */ + [[nodiscard]] XEmbedComponentOptions withAllowForeignWidgetToResizeComponent (bool x = true) const + { + return withMember (*this, &XEmbedComponentOptions::allowForeignWidgetToResizeComponent, x); + } + + /** @see withClientWindow() */ + [[nodiscard]] auto getClientWindow() const { return clientWindow; } + + /** @see withWantsKeyboardFocus() */ + [[nodiscard]] bool getWantsKeyboardFocus() const { return wantsKeyboardFocus; } + + /** @see withAllowForeignWidgetToResizeComponent() */ + [[nodiscard]] bool getAllowForeignWidgetToResizeComponent() const { return allowForeignWidgetToResizeComponent; } + +private: + unsigned long clientWindow{}; + bool wantsKeyboardFocus = true; + bool allowForeignWidgetToResizeComponent = false; +}; + //============================================================================== /** A Linux-specific class that can embed a foreign X11 widget. @@ -75,6 +126,12 @@ class XEmbedComponent : public Component { public: //============================================================================== + /** Creates a JUCE component wrapping a foreign widget. + + Depending on the options passed, this constructor can be used for either + the host initiated or client initiated version of the XEmbedProtocol. + */ + explicit XEmbedComponent (const XEmbedComponentOptions& options); /** Creates a JUCE component wrapping a foreign widget diff --git a/modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp b/modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp index 8f4d6c009d..67adb5abf5 100644 --- a/modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp +++ b/modules/juce_gui_extra/native/juce_XEmbedComponent_linux.cpp @@ -143,23 +143,20 @@ public: public: //============================================================================== - Pimpl (XEmbedComponent& parent, Window x11Window, - bool wantsKeyboardFocus, bool isClientInitiated, bool shouldAllowResize) + Pimpl (XEmbedComponent& parent, const XEmbedComponentOptions& optionsIn) : owner (parent), infoAtom (XWindowSystem::getInstance()->getAtoms().XembedInfo), messageTypeAtom (XWindowSystem::getInstance()->getAtoms().XembedMsgType), - clientInitiated (isClientInitiated), - wantsFocus (wantsKeyboardFocus), - allowResize (shouldAllowResize) + options (optionsIn) { getWidgets().add (this); createHostWindow(); - if (clientInitiated) + if (auto x11Window = options.getClientWindow(); x11Window != 0) setClient (x11Window, true); - owner.setWantsKeyboardFocus (wantsFocus); + owner.setWantsKeyboardFocus (options.getWantsKeyboardFocus()); owner.addComponentListener (this); } @@ -203,7 +200,7 @@ public: // if the client has initiated the component then keep the clients size // otherwise the client should use the host's window' size - if (clientInitiated) + if (options.getClientWindow() != 0) { configureNotify(); } @@ -236,7 +233,7 @@ public: void focusGained (FocusChangeType changeType, FocusChangeDirection direction) { - if (client != 0 && supportsXembed && wantsFocus) + if (client != 0 && supportsXembed && options.getWantsKeyboardFocus()) { updateKeyFocus(); @@ -258,7 +255,7 @@ public: void focusLost (FocusChangeType) { - if (client != 0 && supportsXembed && wantsFocus) + if (client != 0 && supportsXembed && options.getWantsKeyboardFocus()) { sendXEmbedEvent (CurrentTime, XEMBED_FOCUS_OUT); updateKeyFocus(); @@ -276,7 +273,7 @@ public: // You are using the client initiated version of the protocol. You cannot // retrieve the window id of the host. Please read the documentation for // the XEmebedComponent class. - jassert (! clientInitiated); + jassert (options.getClientWindow() == 0); return host; } @@ -354,9 +351,8 @@ private: WindowMapper clientMapper { *this, client }, hostMapper { *this, host }; Atom infoAtom, messageTypeAtom; - bool clientInitiated; - bool wantsFocus = false; - bool allowResize = false; + XEmbedComponentOptions options; + bool supportsXembed = false; int xembedVersion = maxXEmbedVersionToSupport; @@ -557,7 +553,7 @@ private: if (newPeer != nullptr) { - if (wantsFocus) + if (options.getWantsKeyboardFocus()) { keyWindow = SharedKeyWindow::getKeyWindowForPeer (newPeer); updateKeyFocus(); @@ -583,6 +579,8 @@ private: if (auto* peer = owner.getPeer()) peer->getCurrentModifiersRealtime(); + const auto wantsFocus = options.getWantsKeyboardFocus(); + switch (opcode) { case XEMBED_REQUEST_FOCUS: @@ -616,7 +614,7 @@ private: return true; case ConfigureNotify: - if (allowResize) + if (options.getAllowForeignWidgetToResizeComponent()) configureNotify(); else MessageManager::callAsync ([this] { componentMovedOrResized (owner, true, true); }); @@ -747,16 +745,23 @@ private: }; //============================================================================== -XEmbedComponent::XEmbedComponent (bool wantsKeyboardFocus, bool allowForeignWidgetToResizeComponent) - : pimpl (new Pimpl (*this, 0, wantsKeyboardFocus, false, allowForeignWidgetToResizeComponent)) +XEmbedComponent::XEmbedComponent (const XEmbedComponentOptions& options) + : pimpl (new Pimpl (*this, options)) { setOpaque (true); } -XEmbedComponent::XEmbedComponent (unsigned long wID, bool wantsKeyboardFocus, bool allowForeignWidgetToResizeComponent) - : pimpl (new Pimpl (*this, wID, wantsKeyboardFocus, true, allowForeignWidgetToResizeComponent)) +XEmbedComponent::XEmbedComponent (bool wantsKeyboardFocus, bool allowForeignWidgetToResizeComponent) + : XEmbedComponent { XEmbedComponentOptions{}.withWantsKeyboardFocus (wantsKeyboardFocus) + .withAllowForeignWidgetToResizeComponent (allowForeignWidgetToResizeComponent) } +{ +} + +XEmbedComponent::XEmbedComponent (unsigned long wID, bool wantsKeyboardFocus, bool allowForeignWidgetToResizeComponent) + : XEmbedComponent { XEmbedComponentOptions{}.withClientWindow (wID) + .withWantsKeyboardFocus (wantsKeyboardFocus) + .withAllowForeignWidgetToResizeComponent (allowForeignWidgetToResizeComponent) } { - setOpaque (true); } XEmbedComponent::~XEmbedComponent() {}