You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
78 lines
3.7 KiB
78 lines
3.7 KiB
From 2fb31f248fe86c52c1070cbc8b18b24872a4bedc Mon Sep 17 00:00:00 2001
|
|
From: David Tardon <dtardon@redhat.com>
|
|
Date: Fri, 6 May 2016 09:33:37 +0200
|
|
Subject: [PATCH] improve perf. of VCL event dispatch, take II
|
|
|
|
Change-Id: I5052f0c3e2c8739b336da52ef9590e5008255247
|
|
---
|
|
vcl/inc/window.h | 2 ++
|
|
vcl/source/window/event.cxx | 15 ++++++++++++++-
|
|
vcl/source/window/window.cxx | 1 +
|
|
3 files changed, 17 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<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 10a85ed..c7d1777 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 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
|
|
|