From 9ff1d7f8140de1224bb37fba0cb266a58f37e66d Mon Sep 17 00:00:00 2001 From: David Tardon Date: Thu, 5 May 2016 15:53:06 +0200 Subject: [PATCH] improve perf. of VCL event dispatch Anectodal evidence: for removal of 32 slides from 64 slide presentation, time spent in Window::CallEventListeners has been cut down from 70% to 19% of the total time. Change-Id: Ic8fbb44fa935f068e1b18235592dec0d7e71aec7 --- vcl/inc/window.h | 2 ++ vcl/source/window/event.cxx | 13 ++++++++++++- vcl/source/window/window.cxx | 1 + 3 files changed, 15 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 cb39104..68e822b 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 ); } } 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