make welded toolbars on-demand that were previously on-demand

Change-Id: I795723260deb317093e83d951d968e0b3d3a1850
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86531
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/include/sfx2/weldutils.hxx b/include/sfx2/weldutils.hxx
index cfcf545..2486ca9 100644
--- a/include/sfx2/weldutils.hxx
+++ b/include/sfx2/weldutils.hxx
@@ -33,6 +33,7 @@ private:
    weld::Toolbar* m_pToolbar;

    DECL_LINK(SelectHdl, const OString&, void);
    DECL_LINK(ToggleMenuHdl, const OString&, void);

    void CreateController(const OUString& rCommand);

diff --git a/include/svtools/popupwindowcontroller.hxx b/include/svtools/popupwindowcontroller.hxx
index be39cc8..f1df441 100644
--- a/include/svtools/popupwindowcontroller.hxx
+++ b/include/svtools/popupwindowcontroller.hxx
@@ -33,6 +33,7 @@
namespace vcl { class Window; }

class InterimToolbarPopup;
class ToolbarPopupContainer;
class WeldToolbarPopup;

namespace svt
@@ -46,11 +47,13 @@ public:
    PopupWindowController( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
                           const css::uno::Reference< css::frame::XFrame >& xFrame,
                           const OUString& aCommandURL );

    virtual ~PopupWindowController() override;

    void EndPopupMode();

    virtual VclPtr<vcl::Window> createPopupWindow( vcl::Window* pParent ) = 0;
    virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow();

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() override = 0;
@@ -65,9 +68,10 @@ public:

    // XToolbarController
    virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createPopupWindow() override;
    virtual void SAL_CALL click() override;

protected:
    std::unique_ptr<WeldToolbarPopup> mxPopover;
    std::unique_ptr<ToolbarPopupContainer> mxPopoverContainer;
    VclPtr<InterimToolbarPopup> mxInterimPopover;

private:
diff --git a/include/svtools/toolbarmenu.hxx b/include/svtools/toolbarmenu.hxx
index 1ff5079..f066118 100644
--- a/include/svtools/toolbarmenu.hxx
+++ b/include/svtools/toolbarmenu.hxx
@@ -173,16 +173,41 @@ public:
    virtual void GrabFocus() = 0;
};

// we want to create WeldToolbarPopup on-demand when a toolbar dropdown is
// clicked, but the widget to be shown must exist before the dropdown
// is activated, so ToolbarPopupContainer is that widget and the
// contents of the on-demand created WeldToolbarPopup is placed
// within the ToolbarPopupContainer
class SVT_DLLPUBLIC ToolbarPopupContainer
{
private:
    DECL_LINK(FocusHdl, weld::Widget&, void);

protected:
    std::unique_ptr<weld::Builder> m_xBuilder;
    std::unique_ptr<weld::Container> m_xTopLevel;
    std::unique_ptr<weld::Container> m_xContainer;
    std::unique_ptr<WeldToolbarPopup> m_xPopup;
public:
    ToolbarPopupContainer(weld::Widget* pParent);
    ~ToolbarPopupContainer();
    weld::Container* getTopLevel() { return m_xTopLevel.get(); }
    weld::Container* getContainer() { return m_xContainer.get(); }

    void setPopover(std::unique_ptr<WeldToolbarPopup> xPopup);
    void unsetPopover();
};

class SVT_DLLPUBLIC InterimToolbarPopup : public svtools::ToolbarPopup
{
protected:
    VclPtr<vcl::Window> m_xBox;
    std::unique_ptr<weld::Builder> m_xBuilder;
    std::unique_ptr<weld::Container> m_xContainer;

    WeldToolbarPopup* m_pPopup;
    std::unique_ptr<WeldToolbarPopup> m_xPopup;
public:
    InterimToolbarPopup(const css::uno::Reference<css::frame::XFrame>& rFrame, vcl::Window* pParent, WeldToolbarPopup* pPopup);
    InterimToolbarPopup(const css::uno::Reference<css::frame::XFrame>& rFrame, vcl::Window* pParent,
                        std::unique_ptr<WeldToolbarPopup> xPopup);
    weld::Container* getContainer() { return m_xContainer.get(); }
    virtual void dispose() override;
    virtual ~InterimToolbarPopup() override;
diff --git a/include/svx/ParaLineSpacingPopup.hxx b/include/svx/ParaLineSpacingPopup.hxx
index 743894c..4d22cdc 100644
--- a/include/svx/ParaLineSpacingPopup.hxx
+++ b/include/svx/ParaLineSpacingPopup.hxx
@@ -34,6 +34,7 @@ public:

    using svt::ToolboxController::createPopupWindow;
    virtual VclPtr<vcl::Window> createPopupWindow( vcl::Window* pParent ) override;
    virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() override;
diff --git a/include/svx/tbcontrl.hxx b/include/svx/tbcontrl.hxx
index 226160e..e812ce4 100644
--- a/include/svx/tbcontrl.hxx
+++ b/include/svx/tbcontrl.hxx
@@ -231,6 +231,7 @@ public:

    using svt::ToolboxController::createPopupWindow;
    virtual VclPtr<vcl::Window> createPopupWindow( vcl::Window* pParent ) override;
    virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;

    // XSubToolbarController
    virtual sal_Bool SAL_CALL opensSubToolbar() override;
@@ -279,6 +280,7 @@ public:

    using svt::ToolboxController::createPopupWindow;
    virtual VclPtr<vcl::Window> createPopupWindow( vcl::Window* pParent ) override;
    virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() override;
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index e205ea2..6d99c35 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -1956,10 +1956,10 @@ class VCL_DLLPUBLIC Toolbar : virtual public Widget
{
protected:
    Link<const OString&, void> m_aClickHdl;
    Link<const OString&, void> m_aShowMenuHdl;
    Link<const OString&, void> m_aToggleMenuHdl;

    void signal_clicked(const OString& rIdent) { m_aClickHdl.Call(rIdent); }
    void signal_show_menu(const OString& rIdent) { m_aShowMenuHdl.Call(rIdent); }
    void signal_toggle_menu(const OString& rIdent) { m_aToggleMenuHdl.Call(rIdent); }

public:
    virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) = 0;
@@ -1997,9 +1997,7 @@ public:
    virtual vcl::ImageType get_icon_size() const = 0;

    void connect_clicked(const Link<const OString&, void>& rLink) { m_aClickHdl = rLink; }
    // m_aShowMenuHdl is called before the menu is shown.
    // It can be used to populate the menu on demand with set_item_popover/set_item_menu
    void connect_show_menu(const Link<const OString&, void>& rLink) { m_aShowMenuHdl = rLink; }
    void connect_menu_toggled(const Link<const OString&, void>& rLink) { m_aToggleMenuHdl = rLink; }
};

class VCL_DLLPUBLIC SizeGroup
diff --git a/sfx2/source/toolbox/weldutils.cxx b/sfx2/source/toolbox/weldutils.cxx
index 52cf254..112f285 100644
--- a/sfx2/source/toolbox/weldutils.cxx
+++ b/sfx2/source/toolbox/weldutils.cxx
@@ -58,6 +58,7 @@ ToolbarUnoDispatcher::ToolbarUnoDispatcher(weld::Toolbar& rToolbar,
    , m_pToolbar(&rToolbar)
{
    rToolbar.connect_clicked(LINK(this, ToolbarUnoDispatcher, SelectHdl));
    rToolbar.connect_menu_toggled(LINK(this, ToolbarUnoDispatcher, ToggleMenuHdl));

    OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame));
    vcl::ImageType eSize = rToolbar.get_icon_size();
@@ -111,6 +112,15 @@ IMPL_LINK(ToolbarUnoDispatcher, SelectHdl, const OString&, rCommand, void)
        xController->execute(0);
}

IMPL_LINK(ToolbarUnoDispatcher, ToggleMenuHdl, const OString&, rCommand, void)
{
    css::uno::Reference<css::frame::XToolbarController> xController(
        GetControllerForCommand(OUString::fromUtf8(rCommand)));

    if (xController.is())
        xController->click();
}

void ToolbarUnoDispatcher::dispose()
{
    if (!m_pToolbar)
diff --git a/svtools/source/control/toolbarmenu.cxx b/svtools/source/control/toolbarmenu.cxx
index 7b12d91..7d74380 100644
--- a/svtools/source/control/toolbarmenu.cxx
+++ b/svtools/source/control/toolbarmenu.cxx
@@ -1537,27 +1537,65 @@ IMPL_LINK_NOARG(WeldToolbarPopup, FocusHdl, weld::Widget&, void)
    GrabFocus();
}

InterimToolbarPopup::InterimToolbarPopup(const css::uno::Reference<css::frame::XFrame>& rFrame, vcl::Window* pParent, WeldToolbarPopup* pPopup)
ToolbarPopupContainer::ToolbarPopupContainer(weld::Widget* pParent)
    : m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/toolbarpopover.ui"))
    , m_xTopLevel(m_xBuilder->weld_container("ToolbarPopover"))
    , m_xContainer(m_xBuilder->weld_container("container"))
{
    m_xTopLevel->connect_focus_in(LINK(this, ToolbarPopupContainer, FocusHdl));
}

void ToolbarPopupContainer::setPopover(std::unique_ptr<WeldToolbarPopup> xPopup)
{
    m_xPopup = std::move(xPopup);
    // move the WeldToolbarPopup contents into this toolbar so on-demand contents can appear inside a preexisting gtk popover
    // because the arrow for the popover is only enabled if there's a popover set
    m_xPopup->getTopLevel()->move(m_xPopup->getContainer(), m_xContainer.get());
    m_xPopup->GrabFocus();
}

void ToolbarPopupContainer::unsetPopover()
{
    if (!m_xPopup)
        return;
    m_xContainer->move(m_xPopup->getContainer(), m_xPopup->getTopLevel());
    m_xPopup.reset();
}

ToolbarPopupContainer::~ToolbarPopupContainer()
{
    unsetPopover();
}

IMPL_LINK_NOARG(ToolbarPopupContainer, FocusHdl, weld::Widget&, void)
{
    if (m_xPopup)
        m_xPopup->GrabFocus();
}

InterimToolbarPopup::InterimToolbarPopup(const css::uno::Reference<css::frame::XFrame>& rFrame, vcl::Window* pParent,
                                         std::unique_ptr<WeldToolbarPopup> xPopup)
    : ToolbarPopup(rFrame, pParent, "InterimDockParent", "svx/ui/interimdockparent.ui")
    , m_xBox(get<vcl::Window>("box"))
    , m_xBuilder(Application::CreateInterimBuilder(m_xBox.get(), "svx/ui/interimparent.ui"))
    , m_xContainer(m_xBuilder->weld_container("container"))
    , m_pPopup(pPopup)
    , m_xPopup(std::move(xPopup))
{
    // move the WeldToolbarPopup contents into this interim toolbar so welded contents can appear as a dropdown in an unwelded toolbar
    m_pPopup->getTopLevel()->move(m_pPopup->getContainer(), m_xContainer.get());
    m_xPopup->getTopLevel()->move(m_xPopup->getContainer(), m_xContainer.get());
}

void InterimToolbarPopup::GetFocus()
{
    ToolbarPopup::GetFocus();
    m_pPopup->GrabFocus();
    m_xPopup->GrabFocus();
}

void InterimToolbarPopup::dispose()
{
    // move the contents back where it belongs
    m_xContainer->move(m_pPopup->getContainer(), m_pPopup->getTopLevel());
    m_xContainer->move(m_xPopup->getContainer(), m_xPopup->getTopLevel());
    m_xPopup.reset();
    m_xContainer.reset();
    m_xBox.clear();
    ToolbarPopup::dispose();
diff --git a/svtools/source/uno/popupwindowcontroller.cxx b/svtools/source/uno/popupwindowcontroller.cxx
index 7b1e335..50135ad 100644
--- a/svtools/source/uno/popupwindowcontroller.cxx
+++ b/svtools/source/uno/popupwindowcontroller.cxx
@@ -177,7 +177,7 @@ sal_Bool SAL_CALL PopupWindowController::supportsService( const OUString& Servic
void SAL_CALL PopupWindowController::dispose()
{
    mxInterimPopover.clear();
    mxPopover.reset();
    mxPopoverContainer.reset();
    mxImpl.reset();
    svt::ToolboxController::dispose();
}
@@ -207,8 +207,20 @@ void SAL_CALL PopupWindowController::statusChanged( const frame::FeatureStateEve
    }
}

std::unique_ptr<WeldToolbarPopup> PopupWindowController::weldPopupWindow()
{
    return nullptr;
}

Reference< awt::XWindow > SAL_CALL PopupWindowController::createPopupWindow()
{
    if (m_pToolbar)
    {
        mxPopoverContainer->unsetPopover();
        mxPopoverContainer->setPopover(weldPopupWindow());
        return Reference<awt::XWindow>();
    }

    VclPtr< ToolBox > pToolBox = dynamic_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ).get() );
    if( pToolBox )
    {
@@ -237,6 +249,19 @@ Reference< awt::XWindow > SAL_CALL PopupWindowController::createPopupWindow()
    return Reference< awt::XWindow >();
}

void SAL_CALL PopupWindowController::click()
{
    if (m_pToolbar)
    {
        if (m_pToolbar->get_menu_item_active(m_aCommandURL.toUtf8()))
            createPopupWindow();
        else
            mxPopoverContainer->unsetPopover();
    }

    svt::ToolboxController::click();
}

void PopupWindowController::EndPopupMode()
{
    if (m_pToolbar)
diff --git a/svx/UIConfig_svx.mk b/svx/UIConfig_svx.mk
index 070e52ad..f81460e 100644
--- a/svx/UIConfig_svx.mk
+++ b/svx/UIConfig_svx.mk
@@ -106,6 +106,7 @@ $(eval $(call gb_UIConfig_add_uifiles,svx,\
	svx/uiconfig/ui/textcontrolchardialog \
	svx/uiconfig/ui/textcontrolparadialog \
	svx/uiconfig/ui/textunderlinecontrol \
	svx/uiconfig/ui/toolbarpopover \
	svx/uiconfig/ui/xmlsecstatmenu \
	svx/uiconfig/ui/xformspage \
	svx/uiconfig/ui/zoommenu \
diff --git a/svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx b/svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx
index 6a7b7b5..93ced9f 100644
--- a/svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx
+++ b/svx/source/sidebar/paragraph/ParaLineSpacingControl.cxx
@@ -94,7 +94,7 @@ ParaLineSpacingControl::ParaLineSpacingControl(SvxLineSpacingToolBoxControl* pCo

    SetFieldUnit(*mxLineDistAtMetricBox, eUnit);

    SyncFromDocument();
    Initialize();
}

void ParaLineSpacingControl::GrabFocus()
@@ -106,7 +106,7 @@ ParaLineSpacingControl::~ParaLineSpacingControl()
{
}

void ParaLineSpacingControl::SyncFromDocument()
void ParaLineSpacingControl::Initialize()
{
    const SfxPoolItem* pItem(nullptr);
    SfxViewFrame* pCurrent = SfxViewFrame::Current();
diff --git a/svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx b/svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx
index 6d99915..3f5c12f 100644
--- a/svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx
+++ b/svx/source/sidebar/paragraph/ParaLineSpacingControl.hxx
@@ -35,7 +35,7 @@ public:
    virtual ~ParaLineSpacingControl() override;

    /// Setup the widgets with values from the document.
    void SyncFromDocument();
    void Initialize();

    virtual void GrabFocus() override;

diff --git a/svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx b/svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx
index 90099ac7..470e5eb 100644
--- a/svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx
+++ b/svx/source/sidebar/paragraph/ParaLineSpacingPopup.cxx
@@ -37,24 +37,16 @@ void SvxLineSpacingToolBoxControl::initialize( const css::uno::Sequence< css::un
{
    PopupWindowController::initialize(rArguments);

    if (m_pToolbar)
    {
        mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
        m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
    }

    ToolBox* pToolBox = nullptr;
    sal_uInt16 nId = 0;
    bool bVcl = getToolboxId(nId, &pToolBox);

    weld::Widget* pParent;
    if (pToolBox)
        pParent = pToolBox->GetFrameWeld();
    else
        pParent = m_pToolbar;
    mxPopover = std::make_unique<ParaLineSpacingControl>(this, pParent);

    if (bVcl && pToolBox->GetItemCommand(nId) == m_aCommandURL)
    if (getToolboxId(nId, &pToolBox) && pToolBox->GetItemCommand(nId) == m_aCommandURL)
        pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWNONLY | pToolBox->GetItemBits(nId));
    else if (m_pToolbar)
    {
        const OString aId(m_aCommandURL.toUtf8());
        m_pToolbar->set_item_popover(aId, mxPopover->getTopLevel());
    }
}

void SAL_CALL SvxLineSpacingToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
@@ -72,11 +64,15 @@ void SAL_CALL SvxLineSpacingToolBoxControl::execute(sal_Int16 /*KeyModifier*/)
    }
}

std::unique_ptr<WeldToolbarPopup> SvxLineSpacingToolBoxControl::weldPopupWindow()
{
    return std::make_unique<ParaLineSpacingControl>(this, m_pToolbar);
}

VclPtr<vcl::Window> SvxLineSpacingToolBoxControl::createPopupWindow( vcl::Window* pParent )
{
    dynamic_cast<ParaLineSpacingControl&>(*mxPopover).SyncFromDocument();

    mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, mxPopover.get());
    mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
        std::make_unique<ParaLineSpacingControl>(this, pParent->GetFrameWeld()));

    mxInterimPopover->Show();

diff --git a/svx/source/tbxctrls/bulletsnumbering.cxx b/svx/source/tbxctrls/bulletsnumbering.cxx
index d33f790..ba63a41 100644
--- a/svx/source/tbxctrls/bulletsnumbering.cxx
+++ b/svx/source/tbxctrls/bulletsnumbering.cxx
@@ -53,6 +53,7 @@ class NumberingToolBoxControl : public svt::PopupWindowController
public:
    explicit NumberingToolBoxControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
    virtual VclPtr<vcl::Window> createPopupWindow( vcl::Window* pParent ) override;
    std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;

    // XInitialization
    virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
@@ -185,9 +186,15 @@ NumberingToolBoxControl::NumberingToolBoxControl( const css::uno::Reference< css
{
}

std::unique_ptr<WeldToolbarPopup> NumberingToolBoxControl::weldPopupWindow()
{
    return std::make_unique<NumberingPopup>(*this, m_pToolbar, mePageType);
}

VclPtr<vcl::Window> NumberingToolBoxControl::createPopupWindow( vcl::Window* pParent )
{
    mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, mxPopover.get());
    mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
        std::make_unique<NumberingPopup>(*this, pParent->GetFrameWeld(), mePageType));

    mxInterimPopover->Show();

@@ -203,24 +210,19 @@ void SAL_CALL NumberingToolBoxControl::initialize( const css::uno::Sequence< css
    else if ( m_aCommandURL == ".uno:SetOutline" )
        mePageType = NumberingPageType::OUTLINE;

    ToolBoxItemBits nBits = ( mePageType == NumberingPageType::OUTLINE ) ? ToolBoxItemBits::DROPDOWNONLY : ToolBoxItemBits::DROPDOWN;
    if (m_pToolbar)
    {
        mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
        m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
        return;
    }

    ToolBox* pToolBox = nullptr;
    sal_uInt16 nId = 0;
    bool bVcl = getToolboxId(nId, &pToolBox);

    weld::Widget* pParent;
    if (pToolBox)
        pParent = pToolBox->GetFrameWeld();
    else
        pParent = m_pToolbar;
    mxPopover = std::make_unique<NumberingPopup>(*this, pParent, mePageType);

    if (bVcl)
        pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | nBits );
    else if (m_pToolbar)
    if (getToolboxId(nId, &pToolBox))
    {
        const OString aId(m_aCommandURL.toUtf8());
        m_pToolbar->set_item_popover(aId, mxPopover->getTopLevel());
        ToolBoxItemBits nBits = ( mePageType == NumberingPageType::OUTLINE ) ? ToolBoxItemBits::DROPDOWNONLY : ToolBoxItemBits::DROPDOWN;
        pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | nBits );
    }
}

diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx
index 322bf97..2f11f9f 100644
--- a/svx/source/tbxctrls/tbcontrl.cxx
+++ b/svx/source/tbxctrls/tbcontrl.cxx
@@ -3378,32 +3378,12 @@ void SvxColorToolBoxControl::initialize( const css::uno::Sequence<css::uno::Any>
    auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(getCommandURL(), getModuleName());
    OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);

    OString aId(m_aCommandURL.toUtf8());

    if (m_pToolbar)
    {
        EnsurePaletteManager();

        const css::uno::Reference<css::awt::XWindow> xParent = m_xFrame->getContainerWindow();
        weld::Window* pParentFrame = Application::GetFrameWeld(xParent);

        const OString aId(m_aCommandURL.toUtf8());

        auto xPopover = std::make_unique<ColorWindow>(
                            m_aCommandURL,
                            m_xPaletteManager,
                            m_aColorStatus,
                            m_nSlotId,
                            m_xFrame,
                            pParentFrame,
                            MenuOrToolMenuButton(m_pToolbar, aId),
                            m_aColorSelectFunction);

        if ( m_bSplitButton )
            xPopover->SetSelectedHdl( LINK( this, SvxColorToolBoxControl, SelectedHdl ) );

        mxPopover = std::move(xPopover);

        m_pToolbar->set_item_popover(aId, mxPopover->getTopLevel());

        mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
        m_pToolbar->set_item_popover(aId, mxPopoverContainer->getTopLevel());
        m_xBtnUpdater.reset(new svx::ToolboxButtonColorUpdater(m_nSlotId, aId, m_pToolbar, !m_bSplitButton, aCommandLabel, m_xFrame));
        return;
    }
@@ -3460,6 +3440,31 @@ void SvxColorToolBoxControl::setColorSelectFunction(const ColorSelectFunction& a
        m_xPaletteManager->SetColorSelectFunction(aColorSelectFunction);
}

std::unique_ptr<WeldToolbarPopup> SvxColorToolBoxControl::weldPopupWindow()
{
    EnsurePaletteManager();

    const css::uno::Reference<css::awt::XWindow> xParent = m_xFrame->getContainerWindow();
    weld::Window* pParentFrame = Application::GetFrameWeld(xParent);

    const OString aId(m_aCommandURL.toUtf8());

    auto xPopover = std::make_unique<ColorWindow>(
                        m_aCommandURL,
                        m_xPaletteManager,
                        m_aColorStatus,
                        m_nSlotId,
                        m_xFrame,
                        pParentFrame,
                        MenuOrToolMenuButton(m_pToolbar, aId),
                        m_aColorSelectFunction);

    if ( m_bSplitButton )
        xPopover->SetSelectedHdl( LINK( this, SvxColorToolBoxControl, SelectedHdl ) );

    return xPopover;
}

VclPtr<vcl::Window> SvxColorToolBoxControl::createPopupWindow( vcl::Window* pParent )
{
    EnsurePaletteManager();
@@ -3819,29 +3824,28 @@ void SvxCurrencyToolBoxControl::initialize( const css::uno::Sequence< css::uno::
{
    PopupWindowController::initialize(rArguments);

    if (m_pToolbar)
    {
        mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
        m_pToolbar->set_item_popover(m_aCommandURL.toUtf8(), mxPopoverContainer->getTopLevel());
        return;
    }

    ToolBox* pToolBox = nullptr;
    sal_uInt16 nId = 0;
    bool bVcl = getToolboxId(nId, &pToolBox);

    weld::Widget* pParent;
    if (pToolBox)
        pParent = pToolBox->GetFrameWeld();
    else
        pParent = m_pToolbar;
    mxPopover = std::make_unique<SvxCurrencyList_Impl>(this, pParent, m_aFormatString, m_eLanguage);

    if (bVcl && pToolBox->GetItemCommand(nId) == m_aCommandURL)
    if (getToolboxId(nId, &pToolBox) && pToolBox->GetItemCommand(nId) == m_aCommandURL)
        pToolBox->SetItemBits(nId, ToolBoxItemBits::DROPDOWN | pToolBox->GetItemBits(nId));
    else if (m_pToolbar)
    {
        const OString aId(m_aCommandURL.toUtf8());
        m_pToolbar->set_item_popover(aId, mxPopover->getTopLevel());
    }
}

std::unique_ptr<WeldToolbarPopup> SvxCurrencyToolBoxControl::weldPopupWindow()
{
    return std::make_unique<SvxCurrencyList_Impl>(this, m_pToolbar, m_aFormatString, m_eLanguage);
}

VclPtr<vcl::Window> SvxCurrencyToolBoxControl::createPopupWindow( vcl::Window* pParent )
{
    mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent, mxPopover.get());
    mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
        std::make_unique<SvxCurrencyList_Impl>(this, pParent->GetFrameWeld(), m_aFormatString, m_eLanguage));

    mxInterimPopover->Show();

diff --git a/svx/uiconfig/ui/colorwindow.ui b/svx/uiconfig/ui/colorwindow.ui
index 853ce68..23f53b8 100644
--- a/svx/uiconfig/ui/colorwindow.ui
+++ b/svx/uiconfig/ui/colorwindow.ui
@@ -25,7 +25,7 @@
    <property name="no_show_all">True</property>
    <property name="border_width">4</property>
    <child>
      <object class="GtkBox" id="box1">
      <object class="GtkBox" id="container">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
diff --git a/svx/uiconfig/ui/toolbarpopover.ui b/svx/uiconfig/ui/toolbarpopover.ui
new file mode 100644
index 0000000..828bc6e
--- /dev/null
+++ b/svx/uiconfig/ui/toolbarpopover.ui
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface domain="svx">
  <requires lib="gtk+" version="3.18"/>
  <object class="GtkPopover" id="ToolbarPopover">
    <property name="can_focus">False</property>
    <property name="no_show_all">True</property>
    <property name="border_width">4</property>
    <child>
      <object class="GtkBox" id="container">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">6</property>
        <child>
          <placeholder/>
        </child>
      </object>
    </child>
  </object>
</interface>
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 3ef767c..0dd8825 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -950,8 +950,11 @@ private:
    std::map<sal_uInt16, VclPtr<vcl::Window>> m_aFloats;
    std::map<sal_uInt16, VclPtr<PopupMenu>> m_aMenus;

    OString m_sStartShowIdent;

    DECL_LINK(ClickHdl, ToolBox*, void);
    DECL_LINK(DropdownClick, ToolBox*, void);
    DECL_LINK(MenuToggleListener, VclWindowEvent&, void);

public:
    SalInstanceToolbar(ToolBox* pToolBox, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
@@ -1024,6 +1027,9 @@ public:
        sal_uInt16 nItemId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent));
        assert (m_xToolBox->GetItemBits(nItemId) & ToolBoxItemBits::DROPDOWN);

        if (rIdent == m_sStartShowIdent)
            return true;

        auto aFloat = m_aFloats.find(nItemId);
        if (aFloat != m_aFloats.end())
        {
@@ -1045,9 +1051,17 @@ public:

        vcl::Window* pFloat = pPopoverWidget ? pPopoverWidget->getWidget() : nullptr;
        if (pFloat)
        {
            pFloat->AddEventListener(LINK(this, SalInstanceToolbar, MenuToggleListener));
            pFloat->EnableDocking();
        }

        sal_uInt16 nId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent));
        auto xOldFloat = m_aFloats[nId];
        if (xOldFloat)
        {
            xOldFloat->RemoveEventListener(LINK(this, SalInstanceToolbar, MenuToggleListener));
        }
        m_aFloats[nId] = pFloat;
        m_aMenus[nId] = nullptr;
    }
@@ -1161,9 +1175,26 @@ IMPL_LINK_NOARG(SalInstanceToolbar, DropdownClick, ToolBox*, void)
{
    sal_uInt16 nItemId = m_xToolBox->GetCurItemId();

    OString sIdent = m_xToolBox->GetItemCommand(nItemId).toUtf8();
    signal_show_menu(sIdent);
    set_menu_item_active(sIdent, true);
    m_sStartShowIdent = m_xToolBox->GetItemCommand(nItemId).toUtf8();
    signal_toggle_menu(m_sStartShowIdent);
    set_menu_item_active(m_sStartShowIdent, true);
    m_sStartShowIdent.clear();
}

IMPL_LINK(SalInstanceToolbar, MenuToggleListener, VclWindowEvent&, rEvent, void)
{
    if (rEvent.GetId() == VclEventId::WindowEndPopupMode)
    {
        for (auto& rFloat : m_aFloats)
        {
            if (rEvent.GetWindow() == rFloat.second)
            {
                sal_uInt16 nItemId = rFloat.first;
                signal_toggle_menu(m_xToolBox->GetItemCommand(nItemId).toUtf8());
                break;
            }
        }
    }
}

namespace {
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index bc53e4c..d52fb78 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -7118,7 +7118,7 @@ private:
        if (pMenuButton)
        {
            m_aMenuButtonMap[id] = std::make_unique<GtkInstanceMenuButton>(pMenuButton, m_pBuilder, false);
            g_signal_connect(pToolItem, "show-menu", G_CALLBACK(signalItemShowMenu), this);
            g_signal_connect(pMenuButton, "toggled", G_CALLBACK(signalItemToggled), this);
        }
        g_signal_connect(pToolItem, "clicked", G_CALLBACK(signalItemClicked), this);
    }
@@ -7136,17 +7136,23 @@ private:
        signal_clicked(OString(pStr, pStr ? strlen(pStr) : 0));
    }

    static void signalItemShowMenu(GtkMenuToolButton* pItem, gpointer widget)
    static void signalItemToggled(GtkToggleButton* pItem, gpointer widget)
    {
        GtkInstanceToolbar* pThis = static_cast<GtkInstanceToolbar*>(widget);
        SolarMutexGuard aGuard;
        pThis->signal_item_show_menu(pItem);
        pThis->signal_item_toggled(pItem);
    }

    void signal_item_show_menu(GtkMenuToolButton* pItem)
    void signal_item_toggled(GtkToggleButton* pItem)
    {
        const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pItem));
        signal_show_menu(OString(pStr, pStr ? strlen(pStr) : 0));
        for (auto& a : m_aMenuButtonMap)
        {
            if (a.second->getWidget() == GTK_WIDGET(pItem))
            {
                signal_toggle_menu(a.first);
                break;
            }
        }
    }

    static void set_item_image(GtkToolButton* pItem, const css::uno::Reference<css::graphic::XGraphic>& rIcon)
@@ -7189,7 +7195,6 @@ public:
        for (auto& a : m_aMap)
        {
            g_signal_handlers_block_by_func(a.second, reinterpret_cast<void*>(signalItemClicked), this);
            g_signal_handlers_block_by_func(a.second, reinterpret_cast<void*>(signalItemShowMenu), this);
        }
    }

@@ -7197,7 +7202,6 @@ public:
    {
        for (auto& a : m_aMap)
        {
            g_signal_handlers_unblock_by_func(a.second, reinterpret_cast<void*>(signalItemShowMenu), this);
            g_signal_handlers_unblock_by_func(a.second, reinterpret_cast<void*>(signalItemClicked), this);
        }
    }