Blob Blame History Raw
From a00646aeb9fb75174997f9acb6888c60c68d2551 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Fri, 6 May 2016 09:33:37 +0200
Subject: [PATCH] improve perf. of VCL event dispatch, take II

Change-Id: I5052f0c3e2c8739b336da52ef9590e5008255247
---
 vcl/inc/window.h             |  2 ++
 vcl/source/window/event.cxx  | 20 +++++++++++++++++++-
 vcl/source/window/window.cxx |  1 +
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/vcl/inc/window.h b/vcl/inc/window.h
index 5d792de..d6d4eb9 100644
--- a/vcl/inc/window.h
+++ b/vcl/inc/window.h
@@ -230,6 +230,8 @@ public:
     VclPtr<vcl::Window> mpLastFocusWindow;
     VclPtr<vcl::Window> mpDlgCtrlDownWindow;
     std::vector<Link<VclWindowEvent&,void>> maEventListeners;
+    int mnEventListenersIteratingCount;
+    std::set<Link<VclWindowEvent&,void>> maEventListenersDeleted;
     std::vector<Link<VclWindowEvent&,void>> maChildEventListeners;
 
     // The canvas interface for this VCL window. Is persistent after the first GetCanvas() call
diff --git a/vcl/source/window/event.cxx b/vcl/source/window/event.cxx
index c31aa63..8439c4a 100644
--- a/vcl/source/window/event.cxx
+++ b/vcl/source/window/event.cxx
@@ -27,6 +27,8 @@
 #include <svdata.hxx>
 #include <salframe.hxx>
 
+#include <comphelper/scopeguard.hxx>
+
 #include <com/sun/star/awt/MouseEvent.hpp>
 #include <com/sun/star/awt/KeyModifier.hpp>
 #include <com/sun/star/awt/MouseButton.hpp>
@@ -216,11 +218,25 @@ void Window::CallEventListeners( sal_uLong nEvent, void* pData )
     {
         // Copy the list, because this can be destroyed when calling a Link...
         std::vector<Link<VclWindowEvent&,void>> aCopy( mpWindowImpl->maEventListeners );
+        // we use an iterating counter/flag and a set of deleted Link's to avoid O(n^2) behaviour
+        mpWindowImpl->mnEventListenersIteratingCount++;
+        auto& rWindowImpl = *mpWindowImpl;
+        comphelper::ScopeGuard aGuard(
+            [&rWindowImpl, &aDelData]()
+            {
+                if (!aDelData.IsDead())
+                {
+                    rWindowImpl.mnEventListenersIteratingCount--;
+                    if (rWindowImpl.mnEventListenersIteratingCount == 0)
+                        rWindowImpl.maEventListenersDeleted.clear();
+                }
+            }
+        );
         for ( Link<VclWindowEvent&,void>& rLink : aCopy )
         {
             if (aDelData.IsDead()) break;
             // check this hasn't been removed in some re-enterancy scenario fdo#47368
-            if( std::find(mpWindowImpl->maEventListeners.begin(), mpWindowImpl->maEventListeners.end(), rLink) != mpWindowImpl->maEventListeners.end() )
+            if( rWindowImpl.maEventListenersDeleted.find(rLink) == rWindowImpl.maEventListenersDeleted.end() )
                 rLink.Call( aEvent );
         }
     }
@@ -278,6 +294,8 @@ void Window::RemoveEventListener( const Link<VclWindowEvent&,void>& rEventListen
     {
         auto& rListeners = mpWindowImpl->maEventListeners;
         rListeners.erase( std::remove(rListeners.begin(), rListeners.end(), rEventListener ), rListeners.end() );
+        if (mpWindowImpl->mnEventListenersIteratingCount)
+            mpWindowImpl->maEventListenersDeleted.insert(rEventListener);
     }
 }
 
diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
index bd2a662..1b52ab6 100644
--- a/vcl/source/window/window.cxx
+++ b/vcl/source/window/window.cxx
@@ -632,6 +632,7 @@ WindowImpl::WindowImpl( WindowType nType )
     mpLastFocusWindow                   = nullptr;                      // window for focus restore
     mpDlgCtrlDownWindow                 = nullptr;                      // window for dialog control
     mpFirstDel                          = nullptr;                      // Dtor notification list
+    mnEventListenersIteratingCount = 0;
     mpUserData                          = nullptr;                      // user data
     mpCursor                            = nullptr;                      // cursor
     mpControlFont                       = nullptr;                      // font properties
-- 
2.7.3