From 2fb31f248fe86c52c1070cbc8b18b24872a4bedc Mon Sep 17 00:00:00 2001 From: David Tardon 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 | 15 ++++++++++++++- vcl/source/window/window.cxx | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/vcl/inc/window.h b/vcl/inc/window.h index e06a6b1..302e9d0 100644 --- a/vcl/inc/window.h +++ b/vcl/inc/window.h @@ -201,6 +201,8 @@ public: VclPtr mpLastFocusWindow; VclPtr mpDlgCtrlDownWindow; std::vector> maEventListeners; + int mnEventListenersIteratingCount; + std::set> maEventListenersDeleted; std::vector> maChildEventListeners; int mnChildEventListenersIteratingCount; std::set> maChildEventListenersDeleted; diff --git a/vcl/source/window/event.cxx b/vcl/source/window/event.cxx index 10a85ed..c7d1777 100644 --- a/vcl/source/window/event.cxx +++ b/vcl/source/window/event.cxx @@ -216,11 +216,22 @@ void Window::CallEventListeners( sal_uLong nEvent, void* pData ) { // Copy the list, because this can be destroyed when calling a Link... std::vector> 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]() + { + rWindowImpl.mnEventListenersIteratingCount--; + if (rWindowImpl.mnEventListenersIteratingCount == 0) + rWindowImpl.maEventListenersDeleted.clear(); + } + ); for ( Link& rLink : aCopy ) { if (xWindow->IsDisposed()) 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 ); } } @@ -279,6 +290,8 @@ void Window::RemoveEventListener( const Link& 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 f245c47..d1c1ffe 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -615,6 +615,7 @@ WindowImpl::WindowImpl( WindowType nType ) mpNextOverlap = nullptr; // next overlap window of frame mpLastFocusWindow = nullptr; // window for focus restore mpDlgCtrlDownWindow = nullptr; // window for dialog control + mnEventListenersIteratingCount = 0; mnChildEventListenersIteratingCount = 0; mpUserData = nullptr; // user data mpCursor = nullptr; // cursor -- 2.7.4