diff options
author | Noel Grandin <noel@peralex.com> | 2015-12-18 10:08:35 +0200 |
---|---|---|
committer | Noel Grandin <noel@peralex.com> | 2015-12-18 10:53:13 +0200 |
commit | 60e67b387e79185a33eb07bc03b01cd6d0d0a56b (patch) | |
tree | ea2865821e4af156fdbe8619754c5444d379e392 /vcl/source/window | |
parent | 68f411fb19d265ba391e730d16051b5887a30aa3 (diff) |
fix O(n^2) in vcl event broadcasting tdf#90199
Change-Id: If3d7514364589058334369432cdcf4f7586c239d
Diffstat (limited to 'vcl/source/window')
-rw-r--r-- | vcl/source/window/event.cxx | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/vcl/source/window/event.cxx b/vcl/source/window/event.cxx index f90ac286d3ea..c001c7e9ca43 100644 --- a/vcl/source/window/event.cxx +++ b/vcl/source/window/event.cxx @@ -30,6 +30,7 @@ #include <com/sun/star/awt/MouseEvent.hpp> #include <com/sun/star/awt/KeyModifier.hpp> #include <com/sun/star/awt/MouseButton.hpp> +#include <comphelper/scopeguard.hxx> namespace vcl { @@ -238,17 +239,26 @@ void Window::CallEventListeners( sal_uLong nEvent, void* pData ) if ( aDelData.IsDead() ) return; - auto& rChildListeners = pWindow->mpWindowImpl->maChildEventListeners; - if (!rChildListeners.empty()) + auto& rWindowImpl = *pWindow->mpWindowImpl; + if (!rWindowImpl.maChildEventListeners.empty()) { // Copy the list, because this can be destroyed when calling a Link... - std::vector<Link<VclWindowEvent&,void>> aCopy( rChildListeners ); + std::vector<Link<VclWindowEvent&,void>> aCopy( rWindowImpl.maChildEventListeners ); + // we use an iterating counter/flag and a set of deleted Link's to avoid O(n^2) behaviour + rWindowImpl.maChildEventListenersIteratingCount++; + comphelper::ScopeGuard aGuard( + [&rWindowImpl]() + { + if (--rWindowImpl.maChildEventListenersIteratingCount == 0) + rWindowImpl.maChildEventListenersDeleted.clear(); + } + ); for ( Link<VclWindowEvent&,void>& rLink : aCopy ) { if (aDelData.IsDead()) return; - // check this hasn't been removed in some re-enterancy scenario fdo#47368 - if( std::find(rChildListeners.begin(), rChildListeners.end(), rLink) != rChildListeners.end() ) + // Check this hasn't been removed in some re-enterancy scenario fdo#47368. + if( rWindowImpl.maChildEventListenersDeleted.find(rLink) != rWindowImpl.maChildEventListenersDeleted.end() ) rLink.Call( aEvent ); } } @@ -292,6 +302,8 @@ void Window::RemoveChildEventListener( const Link<VclWindowEvent&,void>& rEventL { auto& rListeners = mpWindowImpl->maChildEventListeners; rListeners.erase( std::remove(rListeners.begin(), rListeners.end(), rEventListener ), rListeners.end() ); + if (mpWindowImpl->maChildEventListenersIteratingCount) + mpWindowImpl->maChildEventListenersDeleted.insert(rEventListener); } } |