191a794
From 12776a97a32449f5c0fc6de735c29fc30c0d7d14 Mon Sep 17 00:00:00 2001
8c261e6
From: David Tardon <dtardon@redhat.com>
8c261e6
Date: Tue, 10 May 2016 09:00:20 +0200
8c261e6
Subject: [PATCH] improve perf. of VCL event dispatch
8c261e6
8c261e6
Change-Id: I5052f0c3e2c8739b336da52ef9590e5008255247
8c261e6
---
8c261e6
 vcl/inc/window.h             |  4 +++-
191a794
 vcl/source/window/event.cxx  | 39 ++++++++++++++++++++++++++++++++++++---
8c261e6
 vcl/source/window/window.cxx |  1 +
191a794
 3 files changed, 40 insertions(+), 4 deletions(-)
8c261e6
8c261e6
diff --git a/vcl/inc/window.h b/vcl/inc/window.h
8c261e6
index 67d5f94..60f7e82 100644
8c261e6
--- a/vcl/inc/window.h
8c261e6
+++ b/vcl/inc/window.h
8c261e6
@@ -224,7 +224,9 @@ public:
8c261e6
     VclPtr<vcl::Window> mpNextOverlap;
8c261e6
     VclPtr<vcl::Window> mpLastFocusWindow;
8c261e6
     VclPtr<vcl::Window> mpDlgCtrlDownWindow;
8c261e6
-    VclEventListeners   maEventListeners;
8c261e6
+    std::vector<Link<>> maEventListeners;
8c261e6
+    int mnEventListenersIteratingCount;
8c261e6
+    std::set<Link<>> maEventListenersDeleted;
8c261e6
     VclEventListeners   maChildEventListeners;
8c261e6
 
8c261e6
     // The canvas interface for this VCL window. Is persistent after the first GetCanvas() call
8c261e6
diff --git a/vcl/source/window/event.cxx b/vcl/source/window/event.cxx
191a794
index 35c3e38..cbd5b23 100644
8c261e6
--- a/vcl/source/window/event.cxx
8c261e6
+++ b/vcl/source/window/event.cxx
8c261e6
@@ -18,6 +18,7 @@
8c261e6
  */
8c261e6
 
8c261e6
 #include <vcl/event.hxx>
8c261e6
+#include <vcl/vclevent.hxx>
8c261e6
 #include <vcl/window.hxx>
8c261e6
 #include <vcl/dockwin.hxx>
8c261e6
 #include <vcl/layout.hxx>
8c261e6
@@ -27,6 +28,8 @@
8c261e6
 #include <svdata.hxx>
8c261e6
 #include <salframe.hxx>
8c261e6
 
8c261e6
+#include <comphelper/scopeguard.hxx>
8c261e6
+
8c261e6
 #include <com/sun/star/awt/MouseEvent.hpp>
8c261e6
 #include <com/sun/star/awt/KeyModifier.hpp>
8c261e6
 #include <com/sun/star/awt/MouseButton.hpp>
191a794
@@ -212,7 +215,32 @@ void Window::CallEventListeners( sal_uLong nEvent, void* pData )
8c261e6
     if ( aDelData.IsDead() )
8c261e6
         return;
8c261e6
 
8c261e6
-    mpWindowImpl->maEventListeners.Call( &aEvent );
8c261e6
+    if (!mpWindowImpl->maEventListeners.empty())
8c261e6
+    {
8c261e6
+         // Copy the list, because this can be destroyed when calling a Link...
8c261e6
+         std::vector<Link<>> aCopy( mpWindowImpl->maEventListeners );
8c261e6
+        // we use an iterating counter/flag and a set of deleted Link's to avoid O(n^2) behaviour
8c261e6
+        mpWindowImpl->mnEventListenersIteratingCount++;
8c261e6
+        auto& rWindowImpl = *mpWindowImpl;
8c261e6
+        comphelper::ScopeGuard aGuard(
191a794
+            [&rWindowImpl, &aDelData]()
8c261e6
+            {
191a794
+                if (!aDelData.IsDead())
191a794
+                {
191a794
+                    rWindowImpl.mnEventListenersIteratingCount--;
191a794
+                    if (rWindowImpl.mnEventListenersIteratingCount == 0)
191a794
+                        rWindowImpl.maEventListenersDeleted.clear();
191a794
+                }
8c261e6
+            }
8c261e6
+        );
8c261e6
+        for ( Link<>& rLink : aCopy )
8c261e6
+        {
8c261e6
+            if (aDelData.IsDead()) break;
8c261e6
+            // check this hasn't been removed in some re-enterancy scenario fdo#47368
8c261e6
+            if( rWindowImpl.maEventListenersDeleted.find(rLink) == rWindowImpl.maEventListenersDeleted.end() )
8c261e6
+                rLink.Call( &aEvent );
8c261e6
+        }
8c261e6
+    }
8c261e6
 
8c261e6
     if ( aDelData.IsDead() )
8c261e6
         return;
191a794
@@ -245,13 +273,18 @@ void Window::FireVclEvent( VclSimpleEvent* pEvent )
8c261e6
 
8c261e6
 void Window::AddEventListener( const Link<>& rEventListener )
8c261e6
 {
8c261e6
-    mpWindowImpl->maEventListeners.addListener( rEventListener );
8c261e6
+    mpWindowImpl->maEventListeners.push_back( rEventListener );
8c261e6
 }
8c261e6
 
8c261e6
 void Window::RemoveEventListener( const Link<>& rEventListener )
8c261e6
 {
8c261e6
     if (mpWindowImpl)
8c261e6
-        mpWindowImpl->maEventListeners.removeListener( rEventListener );
8c261e6
+    {
8c261e6
+        auto& rListeners = mpWindowImpl->maEventListeners;
8c261e6
+        rListeners.erase( std::remove(rListeners.begin(), rListeners.end(), rEventListener ), rListeners.end() );
8c261e6
+        if (mpWindowImpl->mnEventListenersIteratingCount)
8c261e6
+            mpWindowImpl->maEventListenersDeleted.insert(rEventListener);
8c261e6
+    }
8c261e6
 }
8c261e6
 
8c261e6
 void Window::AddChildEventListener( const Link<>& rEventListener )
8c261e6
diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
8c261e6
index e8d2b96..cbfc4cd 100644
8c261e6
--- a/vcl/source/window/window.cxx
8c261e6
+++ b/vcl/source/window/window.cxx
8c261e6
@@ -630,6 +630,7 @@ WindowImpl::WindowImpl( WindowType nType )
8c261e6
     mpLastFocusWindow                   = NULL;                      // window for focus restore
8c261e6
     mpDlgCtrlDownWindow                 = NULL;                      // window for dialog control
8c261e6
     mpFirstDel                          = NULL;                      // Dtor notification list
8c261e6
+    mnEventListenersIteratingCount = 0;
8c261e6
     mpUserData                          = NULL;                      // user data
8c261e6
     mpCursor                            = NULL;                      // cursor
8c261e6
     mpControlFont                       = NULL;                      // font properties
8c261e6
-- 
191a794
2.7.3
8c261e6