update credits
[LibreOffice.git] / comphelper / source / misc / accessibleeventnotifier.cxx
blob14ac88c78448fdda254453d8a5840dc71763b7fb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/accessibleeventnotifier.hxx>
21 #include <osl/diagnose.h>
22 #include <rtl/instance.hxx>
23 #include <comphelper/guarding.hxx>
25 using namespace ::com::sun::star::uno;
26 using namespace ::com::sun::star::lang;
27 using namespace ::com::sun::star::accessibility;
28 using namespace ::comphelper;
30 //=====================================================================
31 //= AccessibleEventNotifier
32 //=====================================================================
33 //---------------------------------------------------------------------
34 namespace
36 struct lclMutex
37 : public rtl::Static< ::osl::Mutex, lclMutex > {};
38 struct Clients
39 : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {};
42 //.........................................................................
43 namespace comphelper
45 //.........................................................................
47 //---------------------------------------------------------------------
48 AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId()
50 TClientId nBiggestUsedId = 0;
51 TClientId nFreeId = 0;
53 // look through all registered clients until we find a "gap" in the ids
55 // Note that the following relies on the fact the elements in the map are traveled with
56 // ascending keys (aka client ids)
57 AccessibleEventNotifier::ClientMap &rClients = Clients::get();
58 for ( ClientMap::const_iterator aLookup = rClients.begin();
59 aLookup != rClients.end();
60 ++aLookup
63 TClientId nCurrent = aLookup->first;
64 OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );
66 if ( nCurrent - nBiggestUsedId > 1 )
67 { // found a "gap"
68 nFreeId = nBiggestUsedId + 1;
69 break;
72 nBiggestUsedId = nCurrent;
75 if ( !nFreeId )
76 nFreeId = nBiggestUsedId + 1;
78 OSL_ENSURE( rClients.end() == rClients.find( nFreeId ),
79 "AccessibleEventNotifier::generateId: algorithm broken!" );
81 return nFreeId;
84 //---------------------------------------------------------------------
85 AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( )
87 ::osl::MutexGuard aGuard( lclMutex::get() );
89 // generate a new client id
90 TClientId nNewClientId = generateId( );
92 // the event listeners for the new client
93 EventListeners* pNewListeners = new EventListeners( lclMutex::get() );
94 // note that we're using our own mutex here, so the listener containers for all
95 // our clients share this same mutex.
96 // this is a reminiscense to the days where the notifier was asynchronous. Today this is
97 // completely nonsense, and potentially slowing down the Office me thinks ...
99 // add the client
100 Clients::get().insert( ClientMap::value_type( nNewClientId, pNewListeners ) );
102 // outta here
103 return nNewClientId;
106 //---------------------------------------------------------------------
107 sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos )
109 // look up this client
110 AccessibleEventNotifier::ClientMap &rClients = Clients::get();
111 _rPos = rClients.find( _nClient );
112 OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );
114 return ( rClients.end() != _rPos );
117 //---------------------------------------------------------------------
118 void AccessibleEventNotifier::revokeClient( const TClientId _nClient )
120 ::osl::MutexGuard aGuard( lclMutex::get() );
122 ClientMap::iterator aClientPos;
123 if ( !implLookupClient( _nClient, aClientPos ) )
124 // already asserted in implLookupClient
125 return;
127 // remove it from the clients map
128 delete aClientPos->second;
129 Clients::get().erase( aClientPos );
132 //---------------------------------------------------------------------
133 void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient,
134 const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) )
136 EventListeners * pListeners(0);
139 // rhbz#1001768 drop the mutex before calling disposeAndClear
140 ::osl::MutexGuard aGuard( lclMutex::get() );
142 ClientMap::iterator aClientPos;
143 if (!implLookupClient(_nClient, aClientPos))
144 // already asserted in implLookupClient
145 return;
147 // notify the listeners
148 pListeners = aClientPos->second;
150 // we do not need the entry in the clients map anymore
151 // (do this before actually notifying, because some client
152 // implementations have re-entrance problems and call into
153 // revokeClient while we are notifying from here)
154 Clients::get().erase(aClientPos);
157 // notify the "disposing" event for this client
158 EventObject aDisposalEvent;
159 aDisposalEvent.Source = _rxEventSource;
161 // now really do the notification
162 pListeners->disposeAndClear( aDisposalEvent );
163 delete pListeners;
166 //---------------------------------------------------------------------
167 sal_Int32 AccessibleEventNotifier::addEventListener(
168 const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
170 ::osl::MutexGuard aGuard( lclMutex::get() );
172 ClientMap::iterator aClientPos;
173 if ( !implLookupClient( _nClient, aClientPos ) )
174 // already asserted in implLookupClient
175 return 0;
177 if ( _rxListener.is() )
178 aClientPos->second->addInterface( _rxListener );
180 return aClientPos->second->getLength();
183 //---------------------------------------------------------------------
184 sal_Int32 AccessibleEventNotifier::removeEventListener(
185 const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
187 ::osl::MutexGuard aGuard( lclMutex::get() );
189 ClientMap::iterator aClientPos;
190 if ( !implLookupClient( _nClient, aClientPos ) )
191 // already asserted in implLookupClient
192 return 0;
194 if ( _rxListener.is() )
195 aClientPos->second->removeInterface( _rxListener );
197 return aClientPos->second->getLength();
200 //---------------------------------------------------------------------
201 void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) )
203 Sequence< Reference< XInterface > > aListeners;
205 // --- <mutex lock> -------------------------------
207 ::osl::MutexGuard aGuard( lclMutex::get() );
209 ClientMap::iterator aClientPos;
210 if ( !implLookupClient( _nClient, aClientPos ) )
211 // already asserted in implLookupClient
212 return;
214 // since we're synchronous, again, we want to notify immediately
215 aListeners = aClientPos->second->getElements();
217 // --- </mutex lock> ------------------------------
219 // default handling: loop through all listeners, and notify them
220 const Reference< XInterface >* pListeners = aListeners.getConstArray();
221 const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
222 while ( pListeners != pListenersEnd )
226 static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent );
228 catch( const Exception& )
230 // no assertion, because a broken access remote bridge or something like this
231 // can cause this exception
233 ++pListeners;
237 //.........................................................................
238 } // namespace comphelper
239 //.........................................................................
241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */