Files
libreoffice/vcl/source/app/vclevent.cxx
Stephan Bergmann 3ead3ad52f Gradually typed Link
Turn the Link class into a template abstracting over the link's argument and
return types, but provide default template arguments that keep the generic,
unsafe "void* in, sal_IntPtr out" behvior.  That way, individual uses of the
Link class can be updated over time.

All the related macros are duplicated with ..._TYPED counterparts, that
additionally take the RetType (except for LINK_TYPED, which manages to infer the
relevant types from the supplied Member).

(It would have been attractive to change the "untyped" LinkStubs from taking a
void* to a properly typed ArgType parameter, too, but that would cause
-fsanitize=function to flag uses of "untyped" Link::Call.)

Change-Id: I3b0140378bad99abbf240140ebb4a46a05d2d2f8
2015-04-30 10:20:00 +02:00

171 lines
5.0 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "vcl/vclevent.hxx"
#include "vcl/window.hxx"
#include "svdata.hxx"
#include <com/sun/star/accessibility/XAccessible.hpp>
using ::com::sun::star::uno::Reference;
using ::com::sun::star::accessibility::XAccessible;
TYPEINIT0(VclSimpleEvent);
TYPEINIT1(VclWindowEvent, VclSimpleEvent);
TYPEINIT1(VclMenuEvent, VclSimpleEvent);
VclAccessibleEvent::VclAccessibleEvent( sal_uLong n, const Reference<XAccessible>& rxAccessible ) :
VclSimpleEvent(n),
mxAccessible(rxAccessible)
{
}
VclAccessibleEvent::~VclAccessibleEvent()
{
}
void VclEventListeners::Call( VclSimpleEvent* pEvent ) const
{
if ( m_aListeners.empty() )
return;
// Copy the list, because this can be destroyed when calling a Link...
std::list<Link<>> aCopy( m_aListeners );
std::list<Link<>>::iterator aIter( aCopy.begin() );
std::list<Link<>>::const_iterator aEnd( aCopy.end() );
if( pEvent->IsA( VclWindowEvent::StaticType() ) )
{
VclWindowEvent* pWinEvent = static_cast<VclWindowEvent*>(pEvent);
ImplDelData aDel( pWinEvent->GetWindow() );
while ( aIter != aEnd && ! aDel.IsDead() )
{
Link<> &rLink = *aIter;
// check this hasn't been removed in some re-enterancy scenario fdo#47368
if( std::find(m_aListeners.begin(), m_aListeners.end(), rLink) != m_aListeners.end() )
rLink.Call( pEvent );
++aIter;
}
}
else
{
while ( aIter != aEnd )
{
Link<> &rLink = *aIter;
if( std::find(m_aListeners.begin(), m_aListeners.end(), rLink) != m_aListeners.end() )
rLink.Call( pEvent );
++aIter;
}
}
}
bool VclEventListeners::Process( VclSimpleEvent* pEvent ) const
{
if ( m_aListeners.empty() )
return false;
bool bProcessed = false;
// Copy the list, because this can be destroyed when calling a Link...
std::list<Link<>> aCopy( m_aListeners );
std::list<Link<>>::iterator aIter( aCopy.begin() );
std::list<Link<>>::const_iterator aEnd( aCopy.end() );
while ( aIter != aEnd )
{
if( (*aIter).Call( pEvent ) != 0 )
{
bProcessed = true;
break;
}
++aIter;
}
return bProcessed;
}
void VclEventListeners::addListener( const Link<>& rListener )
{
m_aListeners.push_back( rListener );
}
void VclEventListeners::removeListener( const Link<>& rListener )
{
m_aListeners.remove( rListener );
}
VclEventListeners2::VclEventListeners2()
{
}
VclEventListeners2::~VclEventListeners2()
{
}
void VclEventListeners2::addListener( const Link<>& i_rLink )
{
// ensure uniqueness
for( std::list< Link<> >::const_iterator it = m_aListeners.begin(); it != m_aListeners.end(); ++it )
{
if( *it == i_rLink )
return;
}
m_aListeners.push_back( i_rLink );
}
void VclEventListeners2::removeListener( const Link<>& i_rLink )
{
size_t n = m_aIterators.size();
for( size_t i = 0; i < n; i++ )
{
if( m_aIterators[i].m_aIt != m_aListeners.end() && *m_aIterators[i].m_aIt == i_rLink )
{
m_aIterators[i].m_bWasInvalidated = true;
++m_aIterators[i].m_aIt;
}
}
m_aListeners.remove( i_rLink );
}
void VclEventListeners2::callListeners( VclSimpleEvent* i_pEvent )
{
vcl::DeletionListener aDel( this );
m_aIterators.push_back(ListenerIt(m_aListeners.begin()));
size_t nIndex = m_aIterators.size() - 1;
while( ! aDel.isDeleted() && m_aIterators[ nIndex ].m_aIt != m_aListeners.end() )
{
m_aIterators[ nIndex ].m_aIt->Call( i_pEvent );
if( m_aIterators[ nIndex ].m_bWasInvalidated )
// check if the current element was removed and the iterator increased in the meantime
m_aIterators[ nIndex ].m_bWasInvalidated = false;
else
++m_aIterators[ nIndex ].m_aIt;
}
m_aIterators.pop_back();
}
VclWindowEvent::VclWindowEvent( vcl::Window* pWin, sal_uLong n, void* pDat ) : VclSimpleEvent(n)
{
pWindow = pWin; pData = pDat;
}
VclWindowEvent::~VclWindowEvent() {}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */