tdf#119856: thread-proof creating frames and setting menus

This finally enables opening a new frame and setting its menu from
an extension, but it is still far from stable, loads of threading
landmines like this all over the code

Change-Id: Icf4b67796b0669425ecb7c2c142c21e184024534
Reviewed-on: https://gerrit.libreoffice.org/62737
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/vcl/inc/qt5/Qt5Instance.hxx b/vcl/inc/qt5/Qt5Instance.hxx
index 473f26c..254c814 100644
--- a/vcl/inc/qt5/Qt5Instance.hxx
+++ b/vcl/inc/qt5/Qt5Instance.hxx
@@ -52,6 +52,7 @@ private Q_SLOTS:

Q_SIGNALS:
    bool ImplYieldSignal(bool bWait, bool bHandleAllCurrentEvents);
    std::unique_ptr<SalMenu> createMenuSignal(bool, Menu*);

public:
    explicit Qt5Instance(bool bUseCairo = false);
diff --git a/vcl/inc/qt5/Qt5Menu.hxx b/vcl/inc/qt5/Qt5Menu.hxx
index f3111d0..366b683 100644
--- a/vcl/inc/qt5/Qt5Menu.hxx
+++ b/vcl/inc/qt5/Qt5Menu.hxx
@@ -59,6 +59,9 @@ public:
    unsigned GetItemCount() { return maItems.size(); }
    Qt5MenuItem* GetItemAtPos(unsigned nPos) { return maItems[nPos]; }

Q_SIGNALS:
    void setFrameSignal(const SalFrame* pFrame);

private slots:
    void slotMenuTriggered(Qt5MenuItem* pQItem);
};
diff --git a/vcl/qt5/Qt5Instance.cxx b/vcl/qt5/Qt5Instance.cxx
index f780860..8215b67 100644
--- a/vcl/qt5/Qt5Instance.cxx
+++ b/vcl/qt5/Qt5Instance.cxx
@@ -64,6 +64,8 @@ Qt5Instance::Qt5Instance(bool bUseCairo)
    // is processed before the thread emitting the signal continues
    connect(this, SIGNAL(ImplYieldSignal(bool, bool)), this, SLOT(ImplYield(bool, bool)),
            Qt::BlockingQueuedConnection);
    connect(this, &Qt5Instance::createMenuSignal, this, &Qt5Instance::CreateMenu,
            Qt::BlockingQueuedConnection);
}

Qt5Instance::~Qt5Instance()
@@ -119,6 +121,12 @@ Qt5Instance::CreateVirtualDevice(SalGraphics* pGraphics, long& nDX, long& nDY, D

std::unique_ptr<SalMenu> Qt5Instance::CreateMenu(bool bMenuBar, Menu* pVCLMenu)
{
    if (qApp->thread() != QThread::currentThread())
    {
        SolarMutexReleaser aReleaser;
        return Q_EMIT createMenuSignal(bMenuBar, pVCLMenu);
    }

    Qt5Menu* pSalMenu = new Qt5Menu(bMenuBar);
    pSalMenu->SetMenu(pVCLMenu);
    return std::unique_ptr<SalMenu>(pSalMenu);
diff --git a/vcl/qt5/Qt5Menu.cxx b/vcl/qt5/Qt5Menu.cxx
index 17578ef..5005755 100644
--- a/vcl/qt5/Qt5Menu.cxx
+++ b/vcl/qt5/Qt5Menu.cxx
@@ -24,6 +24,7 @@ Qt5Menu::Qt5Menu(bool bMenuBar)
    , mpFrame(nullptr)
    , mbMenuBar(bMenuBar)
{
    connect(this, &Qt5Menu::setFrameSignal, this, &Qt5Menu::SetFrame, Qt::BlockingQueuedConnection);
}

Qt5Menu::~Qt5Menu() { maItems.clear(); }
@@ -64,6 +65,12 @@ void Qt5Menu::SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned)

void Qt5Menu::SetFrame(const SalFrame* pFrame)
{
    if (qApp->thread() != QThread::currentThread())
    {
        SolarMutexReleaser aReleaser;
        return Q_EMIT setFrameSignal(pFrame);
    }

    SolarMutexGuard aGuard;
    assert(mbMenuBar);
    mpFrame = const_cast<Qt5Frame*>(static_cast<const Qt5Frame*>(pFrame));
@@ -72,9 +79,11 @@ void Qt5Menu::SetFrame(const SalFrame* pFrame)

    Qt5MainWindow* pMainWindow = mpFrame->GetTopLevelWindow();
    if (pMainWindow)
    {
        mpQMenuBar = pMainWindow->menuBar();

    DoFullMenuUpdate(mpVCLMenu);
        DoFullMenuUpdate(mpVCLMenu);
    }
}

void Qt5Menu::DoFullMenuUpdate(Menu* pMenuBar, QMenu* pParentMenu)
diff --git a/vcl/unx/kde5/KDE5SalInstance.cxx b/vcl/unx/kde5/KDE5SalInstance.cxx
index 7c8f278..484920d 100644
--- a/vcl/unx/kde5/KDE5SalInstance.cxx
+++ b/vcl/unx/kde5/KDE5SalInstance.cxx
@@ -46,12 +46,20 @@ KDE5SalInstance::KDE5SalInstance()
    pSVData->maAppData.mxToolkitName = OUString("kde5");

    KDE5SalData::initNWF();

    connect(this, &KDE5SalInstance::createFrameSignal, this, &KDE5SalInstance::CreateFrame,
            Qt::BlockingQueuedConnection);
    connect(this, &KDE5SalInstance::createFilePickerSignal, this,
            &KDE5SalInstance::createFilePicker, Qt::BlockingQueuedConnection);
}

SalFrame* KDE5SalInstance::CreateFrame(SalFrame* pParent, SalFrameStyleFlags nState)
{
    if (!IsMainThread())
    {
        SolarMutexReleaser aReleaser;
        return Q_EMIT createFrameSignal(pParent, nState);
    }
    return new KDE5SalFrame(static_cast<KDE5SalFrame*>(pParent), nState, true);
}

diff --git a/vcl/unx/kde5/KDE5SalInstance.hxx b/vcl/unx/kde5/KDE5SalInstance.hxx
index bfc24de..3cca255 100644
--- a/vcl/unx/kde5/KDE5SalInstance.hxx
+++ b/vcl/unx/kde5/KDE5SalInstance.hxx
@@ -34,7 +34,6 @@ class KDE5SalInstance : public Qt5Instance
    Q_OBJECT
public:
    explicit KDE5SalInstance();
    virtual SalFrame* CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) override;

    virtual bool hasNativeFileSelection() const override { return true; }

@@ -44,10 +43,14 @@ public:
    virtual bool IsMainThread() const override;

Q_SIGNALS:
    SalFrame* createFrameSignal(SalFrame* pParent, SalFrameStyleFlags nStyle);

    css::uno::Reference<css::ui::dialogs::XFilePicker2>
    createFilePickerSignal(const css::uno::Reference<css::uno::XComponentContext>&);

private Q_SLOTS:
    virtual SalFrame* CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) override;

    virtual css::uno::Reference<css::ui::dialogs::XFilePicker2>
    createFilePicker(const css::uno::Reference<css::uno::XComponentContext>&) override;
};