summaryrefslogtreecommitdiff
path: root/vcl/source/window
diff options
context:
space:
mode:
authorNoel Grandin <noel@peralex.com>2015-12-18 10:08:35 +0200
committerNoel Grandin <noel@peralex.com>2015-12-18 10:53:13 +0200
commit60e67b387e79185a33eb07bc03b01cd6d0d0a56b (patch)
treeea2865821e4af156fdbe8619754c5444d379e392 /vcl/source/window
parent68f411fb19d265ba391e730d16051b5887a30aa3 (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.cxx22
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);
}
}