improve perf. of VCL event dispatch

Anectodal evidence: for removal of 32 slides from 64 slide presentation,
time spent in Window::CallEventListeners has been cut down from 70% to
19% of the total time.

Change-Id: Ic8fbb44fa935f068e1b18235592dec0d7e71aec7
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 cb39104..68e822b 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 );
        }
    }
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