diff options
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/window.h | 3 | ||||
-rw-r--r-- | vcl/source/window/event.cxx | 22 |
2 files changed, 20 insertions, 5 deletions
diff --git a/vcl/inc/window.h b/vcl/inc/window.h index 5d792dea7890..e95036910657 100644 --- a/vcl/inc/window.h +++ b/vcl/inc/window.h @@ -39,6 +39,7 @@ #include <vcl/rendersettings.hxx> #include "vcleventlisteners.hxx" #include <vector> +#include <set> struct SalPaintEvent; struct ImplDelData; @@ -231,6 +232,8 @@ public: VclPtr<vcl::Window> mpDlgCtrlDownWindow; std::vector<Link<VclWindowEvent&,void>> maEventListeners; std::vector<Link<VclWindowEvent&,void>> maChildEventListeners; + int maChildEventListenersIteratingCount; + std::set<Link<VclWindowEvent&,void>> maChildEventListenersDeleted; // The canvas interface for this VCL window. Is persistent after the first GetCanvas() call css::uno::WeakReference< css::rendering::XCanvas > mxCanvas; 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); } } |