summaryrefslogtreecommitdiffstats
path: root/vcl
diff options
context:
space:
mode:
authorDavid Tardon <dtardon@redhat.com>2016-05-06 09:33:37 +0200
committerDavid Tardon <dtardon@redhat.com>2016-05-06 09:43:01 +0200
commit2fb31f248fe86c52c1070cbc8b18b24872a4bedc (patch)
treee275a2e0a34d1e125fec1c72fc7cc540078209f3 /vcl
parenttdf#99703 Revert "improve perf. of VCL event dispatch" (diff)
downloadcore-2fb31f248fe86c52c1070cbc8b18b24872a4bedc.tar.gz
core-2fb31f248fe86c52c1070cbc8b18b24872a4bedc.zip
improve perf. of VCL event dispatch, take II
Change-Id: I5052f0c3e2c8739b336da52ef9590e5008255247
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/window.h2
-rw-r--r--vcl/source/window/event.cxx15
-rw-r--r--vcl/source/window/window.cxx1
3 files changed, 17 insertions, 1 deletions
diff --git a/vcl/inc/window.h b/vcl/inc/window.h
index e06a6b1d07c9..302e9d03541b 100644
--- a/vcl/inc/window.h
+++ b/vcl/inc/window.h
@@ -201,6 +201,8 @@ public:
VclPtr<vcl::Window> mpLastFocusWindow;
VclPtr<vcl::Window> mpDlgCtrlDownWindow;
std::vector<Link<VclWindowEvent&,void>> maEventListeners;
+ int mnEventListenersIteratingCount;
+ std::set<Link<VclWindowEvent&,void>> maEventListenersDeleted;
std::vector<Link<VclWindowEvent&,void>> maChildEventListeners;
int mnChildEventListenersIteratingCount;
std::set<Link<VclWindowEvent&,void>> maChildEventListenersDeleted;
diff --git a/vcl/source/window/event.cxx b/vcl/source/window/event.cxx
index 10a85ed368db..c7d17778f9cd 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<Link<VclWindowEvent&,void>> 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<VclWindowEvent&,void>& 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<VclWindowEvent&,void>& 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 f245c475ee7b..d1c1ffe0dc49 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