compilerplugins/clang/badstatics.cxx |    1 
 vcl/inc/jsdialog/jsdialogbuilder.hxx |    9 +++++
 vcl/jsdialog/jsdialogbuilder.cxx     |   56 +++++++++++++++++++++++++++++++++--
 3 files changed, 64 insertions(+), 2 deletions(-)

New commits:
commit 09847cdbd435c1f6ac8c0ac0256f8be488edd194
Author:     Szymon Kłos <eszka...@gmail.com>
AuthorDate: Wed May 18 23:28:30 2022 +0200
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Tue May 31 22:09:42 2022 +0200

    jsdialog: introduce popup management
    
    Popup windows are managed by vcl (some moving between parents
    happens on show/hide popup).
    
    We need to access correct popup window to correctly close
    popup in LOK. So remember popup instances.
    
    Change-Id: I9e1ba18ded5a1bf675f95bd7178043eebd9bbd5a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134576
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mert Tumer <mert.tu...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134675
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135197
    Tested-by: Jenkins
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>

diff --git a/compilerplugins/clang/badstatics.cxx 
b/compilerplugins/clang/badstatics.cxx
index 9539559f699e..3b80278a2f4f 100644
--- a/compilerplugins/clang/badstatics.cxx
+++ b/compilerplugins/clang/badstatics.cxx
@@ -208,6 +208,7 @@ public:
                     .Class("ScDocument").GlobalNamespace()) // not owning
                 || name == "s_aLOKWindowsMap" // LOK only, guarded by assert, 
and LOK never tries to perform a VCL cleanup
                 || name == "s_aLOKWeldBuildersMap" // LOK only, similar case 
as above
+                || name == "s_aLOKPopupsMap" // LOK only, similar case as above
                 || name == "m_pNotebookBarWeldedWrapper" // LOK only, warning 
about map's key, no VCL cleanup performed
                 || name == "gStaticManager" // vcl/source/graphic/Manager.cxx 
- stores non-owning pointers
                 || name == "aThreadedInterpreterPool"    // 
ScInterpreterContext(Pool), not owning
diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx 
b/vcl/inc/jsdialog/jsdialogbuilder.hxx
index 0b0289240bf6..a25aeac55c10 100644
--- a/vcl/inc/jsdialog/jsdialogbuilder.hxx
+++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx
@@ -304,6 +304,11 @@ public:
                                weld::Widget* pWidget);
     static void RemoveWindowWidget(const std::string& nWindowId);
 
+    // we need to remember original popup window to close it properly (its 
handled by vcl)
+    static void RememberPopup(const std::string& nWindowId, 
VclPtr<vcl::Window> pWidget);
+    static void ForgetPopup(const std::string& nWindowId);
+    static vcl::Window* FindPopup(const std::string& nWindowId);
+
 private:
     const std::string& GetTypeOfJSON() const;
     VclPtr<vcl::Window>& GetContentWindow();
@@ -700,6 +705,8 @@ public:
 
 class JSPopover : public JSWidget<SalInstancePopover, DockingWindow>
 {
+    vcl::LOKWindowId mnWindowId;
+
 public:
     JSPopover(JSDialogSender* pSender, DockingWindow* pPopover, 
SalInstanceBuilder* pBuilder,
               bool bTakeOwnership);
@@ -707,6 +714,8 @@ public:
     virtual void popup_at_rect(weld::Widget* pParent, const tools::Rectangle& 
rRect,
                                weld::Placement ePlace = 
weld::Placement::Under) override;
     virtual void popdown() override;
+
+    void set_window_id(vcl::LOKWindowId nWindowId) { mnWindowId = nWindowId; }
 };
 
 class JSBox : public JSWidget<SalInstanceBox, VclBox>
diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx
index b1ca111a07f7..3648d33b3ebc 100644
--- a/vcl/jsdialog/jsdialogbuilder.cxx
+++ b/vcl/jsdialog/jsdialogbuilder.cxx
@@ -27,6 +27,14 @@
 #include <cppuhelper/supportsservice.hxx>
 #include <utility>
 
+static std::map<std::string, vcl::Window*>& GetLOKPopupsMap()
+{
+    // Map to remember the LOKWindowId <-> vcl popup binding.
+    static std::map<std::string, vcl::Window*> s_aLOKPopupsMap;
+
+    return s_aLOKPopupsMap;
+}
+
 namespace
 {
 void response_help(vcl::Window* pWindow)
@@ -670,6 +678,8 @@ JSInstanceBuilder::~JSInstanceBuilder()
                           [it](std::string& sId) { 
it->second.erase(sId.c_str()); });
         }
     }
+
+    GetLOKPopupsMap().erase(std::to_string(m_nWindowId));
 }
 
 std::map<std::string, WidgetMap>& JSInstanceBuilder::GetLOKWeldWidgetsMap()
@@ -762,6 +772,28 @@ void JSInstanceBuilder::RemoveWindowWidget(const 
std::string& nWindowId)
     }
 }
 
+void JSInstanceBuilder::RememberPopup(const std::string& nWindowId, 
VclPtr<vcl::Window> pWidget)
+{
+    GetLOKPopupsMap()[nWindowId] = pWidget;
+}
+
+void JSInstanceBuilder::ForgetPopup(const std::string& nWindowId)
+{
+    auto it = GetLOKPopupsMap().find(nWindowId);
+    if (it != GetLOKPopupsMap().end())
+        GetLOKPopupsMap().erase(it);
+}
+
+vcl::Window* JSInstanceBuilder::FindPopup(const std::string& nWindowId)
+{
+    const auto it = GetLOKPopupsMap().find(nWindowId);
+
+    if (it != GetLOKPopupsMap().end())
+        return it->second;
+
+    return nullptr;
+}
+
 const std::string& JSInstanceBuilder::GetTypeOfJSON() const { return 
m_sTypeOfJSON; }
 
 VclPtr<vcl::Window>& JSInstanceBuilder::GetContentWindow()
@@ -1048,8 +1080,9 @@ std::unique_ptr<weld::MenuButton> 
JSInstanceBuilder::weld_menu_button(const OStr
 std::unique_ptr<weld::Popover> JSInstanceBuilder::weld_popover(const OString& 
id)
 {
     DockingWindow* pDockingWindow = m_xBuilder->get<DockingWindow>(id);
-    std::unique_ptr<weld::Popover> pWeldWidget(
-        pDockingWindow ? new JSPopover(this, pDockingWindow, this, false) : 
nullptr);
+    JSPopover* pPopover
+        = pDockingWindow ? new JSPopover(this, pDockingWindow, this, false) : 
nullptr;
+    std::unique_ptr<weld::Popover> pWeldWidget(pPopover);
     if (pDockingWindow)
     {
         assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed");
@@ -1063,6 +1096,10 @@ std::unique_ptr<weld::Popover> 
JSInstanceBuilder::weld_popover(const OString& id
             m_aParentDialog = pPopupRoot;
             m_aWindowToRelease = pPopupRoot;
             m_nWindowId = m_aParentDialog->GetLOKWindowId();
+
+            pPopover->set_window_id(m_nWindowId);
+            JSInstanceBuilder::RememberPopup(std::to_string(m_nWindowId), 
pDockingWindow);
+
             InsertWindowToMap(getMapIdFromWindowId());
             initializeSender(GetNotifierWindow(), GetContentWindow(), 
GetTypeOfJSON());
         }
@@ -1464,10 +1501,16 @@ void JSToolbar::set_menu_item_active(const OString& 
rIdent, bool bActive)
     if (pPopupRoot)
     {
         if (bActive)
+        {
+            
JSInstanceBuilder::RememberPopup(std::to_string(pPopupRoot->GetLOKWindowId()), 
pFloat);
             sendPopup(pPopupRoot, m_xToolBox->get_id(),
                       OStringToOUString(rIdent, RTL_TEXTENCODING_ASCII_US));
+        }
         else if (bWasActive)
+        {
+            
JSInstanceBuilder::ForgetPopup(std::to_string(pPopupRoot->GetLOKWindowId()));
             sendClosePopup(pPopupRoot->GetLOKWindowId());
+        }
     }
 }
 
@@ -1755,8 +1798,17 @@ void JSPopover::popup_at_rect(weld::Widget* pParent, 
const tools::Rectangle& rRe
 
 void JSPopover::popdown()
 {
+    vcl::Window* pPopup = 
JSInstanceBuilder::FindPopup(std::to_string(mnWindowId));
+
+    if (pPopup)
+    {
+        sendClosePopup(mnWindowId);
+        vcl::Window::GetDockingManager()->EndPopupMode(pPopup);
+    }
+
     if (getWidget() && getWidget()->GetChild(0))
         sendClosePopup(getWidget()->GetChild(0)->GetLOKWindowId());
+
     SalInstancePopover::popdown();
 }
 

Reply via email to