Resolves: tdf#122404 unlock just the toplevels that were locked

push what toplevels got locked to just unlock those ones. otherwise the just
dismissed toplevel may still be present in the Application toplevel list.

merge all the similar examples of this.

Change-Id: I77c0d55d1e4b3bcc3b8d88fef00ba289edd1e831
Reviewed-on: https://gerrit.libreoffice.org/66078
Tested-by: Jenkins
Tested-by: Xisco Faulí <xiscofauli@libreoffice.org>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/desktop/source/deployment/gui/dp_gui_dialog2.cxx b/desktop/source/deployment/gui/dp_gui_dialog2.cxx
index 62e2e30..765ac22 100644
--- a/desktop/source/deployment/gui/dp_gui_dialog2.cxx
+++ b/desktop/source/deployment/gui/dp_gui_dialog2.cxx
@@ -340,7 +340,6 @@ DialogHelper::DialogHelper(const uno::Reference< uno::XComponentContext > &xCont
                           Dialog *pWindow)
    : m_xVCLWindow(pWindow)
    , m_nEventID(nullptr)
    , m_nBusy(0)
{
    m_xContext = xContext;
}
@@ -462,34 +461,6 @@ void DialogHelper::PostUserEvent( const Link<void*,void>& rLink, void* pCaller )
    m_nEventID = Application::PostUserEvent( rLink, pCaller, true/*bReferenceLink*/ );
}

void DialogHelper::incBusy()
{
    ++m_nBusy;
    // lock any toplevel windows from being closed until busy is over
    // ensure any dialogs are reset before entering
    vcl::Window *xTopWin = Application::GetFirstTopLevelWindow();
    while (xTopWin)
    {
        if (xTopWin != m_xVCLWindow)
            xTopWin->IncModalCount();
        xTopWin = Application::GetNextTopLevelWindow(xTopWin);
    }
}

void DialogHelper::decBusy()
{
    --m_nBusy;
    // unlock any toplevel windows from being closed until busy is over
    // ensure any dialogs are reset before entering
    vcl::Window *xTopWin = Application::GetFirstTopLevelWindow();
    while (xTopWin)
    {
        if (xTopWin != m_xVCLWindow)
            xTopWin->DecModalCount();
        xTopWin = Application::GetNextTopLevelWindow(xTopWin);
    }
}

//                             ExtMgrDialog
ExtMgrDialog::ExtMgrDialog(vcl::Window *pParent, TheExtensionManager *pManager, Dialog::InitFlag eFlag)
    : ModelessDialog(pParent, "ExtensionManagerDialog", "desktop/ui/extensionmanager.ui", eFlag)
diff --git a/desktop/source/deployment/gui/dp_gui_dialog2.hxx b/desktop/source/deployment/gui/dp_gui_dialog2.hxx
index dd0dc8b..a2d88c0f 100644
--- a/desktop/source/deployment/gui/dp_gui_dialog2.hxx
+++ b/desktop/source/deployment/gui/dp_gui_dialog2.hxx
@@ -29,6 +29,7 @@
#include <vcl/prgsbar.hxx>
#include <vcl/timer.hxx>
#include <vcl/idle.hxx>
#include <vcl/waitobj.hxx>
#include <vcl/weld.hxx>

#include <svtools/svmedit.hxx>
@@ -47,6 +48,9 @@
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
#include <com/sun/star/util/XModifyListener.hpp>

#include <stack>
#include <vector>

namespace dp_gui {


@@ -60,7 +64,7 @@ class DialogHelper
    css::uno::Reference< css::uno::XComponentContext > m_xContext;
    VclPtr<Dialog>  m_xVCLWindow;
    ImplSVEvent *   m_nEventID;
    int             m_nBusy;
    TopLevelWindowLocker m_aBusy;

public:
                    DialogHelper( const css::uno::Reference< css::uno::XComponentContext > &,
@@ -91,14 +95,13 @@ public:
                                               const char* pResID,
                                               bool &bHadWarning );

    void            incBusy();
    void            decBusy();
    bool            isBusy() const { return m_nBusy > 0; }
    void            incBusy() { m_aBusy.incBusy(m_xVCLWindow); }
    void            decBusy() { m_aBusy.decBusy(); }
    bool            isBusy() const { return m_aBusy.isBusy(); }
    bool            installExtensionWarn(const OUString &rExtensionURL);
    bool            installForAllUsers(bool &bInstallForAll);
};


class ExtMgrDialog : public ModelessDialog,
                     public DialogHelper
{
diff --git a/filter/source/xsltdialog/xmlfiltersettingsdialog.cxx b/filter/source/xsltdialog/xmlfiltersettingsdialog.cxx
index a65b582..3aef692 100644
--- a/filter/source/xsltdialog/xmlfiltersettingsdialog.cxx
+++ b/filter/source/xsltdialog/xmlfiltersettingsdialog.cxx
@@ -132,32 +132,6 @@ void XMLFilterSettingsDialog::dispose()
    ModelessDialog::dispose();
}

void XMLFilterSettingsDialog::incBusy()
{
    // lock any toplevel windows from being closed until busy is over
    // ensure any dialogs are reset before entering
    vcl::Window *xTopWin = Application::GetFirstTopLevelWindow();
    while (xTopWin)
    {
        if (xTopWin != this)
            xTopWin->IncModalCount();
        xTopWin = Application::GetNextTopLevelWindow(xTopWin);
    }
}

void XMLFilterSettingsDialog::decBusy()
{
    // unlock any toplevel windows from being closed until busy is over
    // ensure any dialogs are reset before entering
    vcl::Window *xTopWin = Application::GetFirstTopLevelWindow();
    while (xTopWin)
    {
        if (xTopWin != this)
            xTopWin->DecModalCount();
        xTopWin = Application::GetNextTopLevelWindow(xTopWin);
    }
}

IMPL_LINK(XMLFilterSettingsDialog, ClickHdl_Impl, Button *, pButton, void )
{
    // tdf#122171 block closing libreoffice until the following dialog is dismissed
diff --git a/filter/source/xsltdialog/xmlfiltersettingsdialog.hxx b/filter/source/xsltdialog/xmlfiltersettingsdialog.hxx
index e1e1d82..6c1e89c 100644
--- a/filter/source/xsltdialog/xmlfiltersettingsdialog.hxx
+++ b/filter/source/xsltdialog/xmlfiltersettingsdialog.hxx
@@ -27,6 +27,7 @@
#include <vcl/dialog.hxx>
#include <vcl/layout.hxx>
#include <vcl/svtabbx.hxx>
#include <vcl/waitobj.hxx>
#include <svl/poolitem.hxx>
#include <unotools/moduleoptions.hxx>

@@ -109,8 +110,8 @@ private:
    void    initFilterList();
    void    disposeFilterList();

    void    incBusy();
    void    decBusy();
    void    incBusy() { maBusy.incBusy(this); }
    void    decBusy() { maBusy.decBusy(); }

    bool    insertOrEdit( filter_info_impl* pNewInfo, const filter_info_impl* pOldInfo = nullptr );

@@ -126,6 +127,7 @@ private:

    std::vector< std::unique_ptr<filter_info_impl> > maFilterVector;

    TopLevelWindowLocker maBusy;
    VclPtr<XMLFilterListBox>   m_pFilterListBox;
    VclPtr<SvxPathControl> m_pCtrlFilterList;
    VclPtr<PushButton> m_pPBNew;
diff --git a/include/sfx2/sfxhelp.hxx b/include/sfx2/sfxhelp.hxx
index eaee534..d7afeb2 100644
--- a/include/sfx2/sfxhelp.hxx
+++ b/include/sfx2/sfxhelp.hxx
@@ -40,8 +40,6 @@ private:
    SAL_DLLPRIVATE virtual bool Start(const OUString& rURL, weld::Widget* pWidget) override;
    SAL_DLLPRIVATE static OUString GetHelpModuleName_Impl(const OUString &rHelpId);
    SAL_DLLPRIVATE static OUString CreateHelpURL_Impl( const OUString& aCommandURL, const OUString& rModuleName );
    SAL_DLLPRIVATE static void incBusy(const vcl::Window* pParent);
    SAL_DLLPRIVATE static void decBusy(const vcl::Window* pParent);

public:
    SfxHelp();
diff --git a/include/vcl/waitobj.hxx b/include/vcl/waitobj.hxx
index daf0e2a..858f49d 100644
--- a/include/vcl/waitobj.hxx
+++ b/include/vcl/waitobj.hxx
@@ -23,6 +23,9 @@
#include <vcl/dllapi.h>
#include <vcl/window.hxx>

#include <stack>
#include <vector>

class VCL_DLLPUBLIC WaitObject
{
private:
@@ -37,6 +40,18 @@ public:
                ~WaitObject();
};

class VCL_DLLPUBLIC TopLevelWindowLocker
{
private:
    std::stack<std::vector<VclPtr<vcl::Window>>> m_aBusyStack;
public:
    // lock all toplevels, except the argument
    void incBusy(const vcl::Window* pIgnore);
    // unlock previous lock
    void decBusy();
    bool isBusy() const { return !m_aBusyStack.empty(); }
};

#endif // INCLUDED_VCL_WAITOBJ_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/appl/sfxhelp.cxx b/sfx2/source/appl/sfxhelp.cxx
index 08de23e..169d6a6 100644
--- a/sfx2/source/appl/sfxhelp.cxx
+++ b/sfx2/source/appl/sfxhelp.cxx
@@ -60,6 +60,7 @@
#include <rtl/uri.hxx>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/layout.hxx>
#include <vcl/waitobj.hxx>
#include <vcl/weld.hxx>
#include <svtools/ehdl.hxx>
#include <svtools/sfxecode.hxx>
@@ -1023,32 +1024,6 @@ namespace
    }
}

void SfxHelp::incBusy(const vcl::Window* pParent)
{
    // lock any toplevel windows from being closed until busy is over
    // ensure any dialogs are reset before entering
    vcl::Window *xTopWin = Application::GetFirstTopLevelWindow();
    while (xTopWin)
    {
        if (xTopWin != pParent)
            xTopWin->IncModalCount();
        xTopWin = Application::GetNextTopLevelWindow(xTopWin);
    }
}

void SfxHelp::decBusy(const vcl::Window* pParent)
{
    // unlock any toplevel windows from being closed until busy is over
    // ensure any dialogs are reset before entering
    vcl::Window *xTopWin = Application::GetFirstTopLevelWindow();
    while (xTopWin)
    {
        if (xTopWin != pParent)
            xTopWin->DecModalCount();
        xTopWin = Application::GetNextTopLevelWindow(xTopWin);
    }
}

bool SfxHelp::Start_Impl(const OUString& rURL, const vcl::Window* pWindow, const OUString& rKeyword)
{
    OUStringBuffer aHelpRootURL("vnd.sun.star.help://");
@@ -1155,9 +1130,11 @@ bool SfxHelp::Start_Impl(const OUString& rURL, const vcl::Window* pWindow, const

            pWindow = GetBestParent(pWindow);

            TopLevelWindowLocker aBusy;

            if(bShowOfflineHelpPopUp)
            {
                incBusy(pWindow);
                aBusy.incBusy(pWindow);
                std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pWindow ? pWindow->GetFrameWeld() : nullptr, "sfx/ui/helpmanual.ui"));
                std::unique_ptr<weld::MessageDialog> xQueryBox(xBuilder->weld_message_dialog("onlinehelpmanual"));
                std::unique_ptr<weld::CheckButton> m_xHideOfflineHelpCB(xBuilder->weld_check_button("hidedialog"));
@@ -1168,7 +1145,7 @@ bool SfxHelp::Start_Impl(const OUString& rURL, const vcl::Window* pWindow, const
                short OnlineHelpBox = xQueryBox->run();
                bShowOfflineHelpPopUp = OnlineHelpBox != RET_OK;
                aHelpOptions.SetOfflineHelpPopUp(!m_xHideOfflineHelpCB->get_state());
                decBusy(pWindow);
                aBusy.decBusy();
            }
            if(!bShowOfflineHelpPopUp)
            {
@@ -1176,10 +1153,10 @@ bool SfxHelp::Start_Impl(const OUString& rURL, const vcl::Window* pWindow, const
                    return true;
                else
                {
                    incBusy(pWindow);
                    aBusy.incBusy(pWindow);
                    NoHelpErrorBox aErrBox(pWindow ? pWindow->GetFrameWeld() : nullptr);
                    aErrBox.run();
                    decBusy(pWindow);
                    aBusy.decBusy();
                    return false;
                }
            }
diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx
index 71542d8..4b6a019 100644
--- a/vcl/source/window/dialog.cxx
+++ b/vcl/source/window/dialog.cxx
@@ -43,6 +43,7 @@
#include <vcl/layout.hxx>
#include <vcl/svapp.hxx>
#include <vcl/event.hxx>
#include <vcl/waitobj.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/button.hxx>
#include <vcl/mnemonic.hxx>
@@ -1548,4 +1549,28 @@ void Dialog::Activate()
    SystemWindow::Activate();
}

void TopLevelWindowLocker::incBusy(const vcl::Window* pIgnore)
{
    // lock any toplevel windows from being closed until busy is over
    std::vector<VclPtr<vcl::Window>> aTopLevels;
    vcl::Window *pTopWin = Application::GetFirstTopLevelWindow();
    while (pTopWin)
    {
        if (pTopWin != pIgnore)
            aTopLevels.push_back(pTopWin);
        pTopWin = Application::GetNextTopLevelWindow(pTopWin);
    }
    for (auto& a : aTopLevels)
        a->IncModalCount();
    m_aBusyStack.push(aTopLevels);
}

void TopLevelWindowLocker::decBusy()
{
    // unlock locked toplevel windows from being closed now busy is over
    for (auto& a : m_aBusyStack.top())
        a->DecModalCount();
    m_aBusyStack.pop();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */