1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_comphelper.hxx" 30 #include <comphelper/accessibleeventnotifier.hxx> 31 #include <osl/diagnose.h> 32 #include <rtl/instance.hxx> 33 #include <comphelper/guarding.hxx> 34 35 using namespace ::com::sun::star::uno; 36 using namespace ::com::sun::star::lang; 37 using namespace ::com::sun::star::accessibility; 38 using namespace ::comphelper; 39 40 //===================================================================== 41 //= AccessibleEventNotifier 42 //===================================================================== 43 //--------------------------------------------------------------------- 44 namespace 45 { 46 struct lclMutex 47 : public rtl::Static< ::osl::Mutex, lclMutex > {}; 48 struct Clients 49 : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {}; 50 } 51 52 //......................................................................... 53 namespace comphelper 54 { 55 //......................................................................... 56 57 //--------------------------------------------------------------------- 58 AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId() 59 { 60 TClientId nBiggestUsedId = 0; 61 TClientId nFreeId = 0; 62 63 // look through all registered clients until we find a "gap" in the ids 64 65 // Note that the following relies on the fact the elements in the map are traveled with 66 // ascending keys (aka client ids) 67 AccessibleEventNotifier::ClientMap &rClients = Clients::get(); 68 for ( ClientMap::const_iterator aLookup = rClients.begin(); 69 aLookup != rClients.end(); 70 ++aLookup 71 ) 72 { 73 TClientId nCurrent = aLookup->first; 74 OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" ); 75 76 if ( nCurrent - nBiggestUsedId > 1 ) 77 { // found a "gap" 78 nFreeId = nBiggestUsedId + 1; 79 break; 80 } 81 82 nBiggestUsedId = nCurrent; 83 } 84 85 if ( !nFreeId ) 86 nFreeId = nBiggestUsedId + 1; 87 88 OSL_ENSURE( rClients.end() == rClients.find( nFreeId ), 89 "AccessibleEventNotifier::generateId: algorithm broken!" ); 90 91 return nFreeId; 92 } 93 94 //--------------------------------------------------------------------- 95 AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( ) 96 { 97 ::osl::MutexGuard aGuard( lclMutex::get() ); 98 99 // generate a new client id 100 TClientId nNewClientId = generateId( ); 101 102 // the event listeners for the new client 103 EventListeners* pNewListeners = new EventListeners( lclMutex::get() ); 104 // note that we're using our own mutex here, so the listener containers for all 105 // our clients share this same mutex. 106 // this is a reminiscense to the days where the notifier was asynchronous. Today this is 107 // completely nonsense, and potentially slowing down the Office me thinks ... 108 109 // add the client 110 Clients::get().insert( ClientMap::value_type( nNewClientId, pNewListeners ) ); 111 112 // outta here 113 return nNewClientId; 114 } 115 116 //--------------------------------------------------------------------- 117 sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos ) 118 { 119 // look up this client 120 AccessibleEventNotifier::ClientMap &rClients = Clients::get(); 121 _rPos = rClients.find( _nClient ); 122 OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" ); 123 124 return ( rClients.end() != _rPos ); 125 } 126 127 //--------------------------------------------------------------------- 128 void AccessibleEventNotifier::revokeClient( const TClientId _nClient ) 129 { 130 ::osl::MutexGuard aGuard( lclMutex::get() ); 131 132 ClientMap::iterator aClientPos; 133 if ( !implLookupClient( _nClient, aClientPos ) ) 134 // already asserted in implLookupClient 135 return; 136 137 // remove it from the clients map 138 delete aClientPos->second; 139 Clients::get().erase( aClientPos ); 140 } 141 142 //--------------------------------------------------------------------- 143 void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient, 144 const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) ) 145 { 146 ::osl::MutexGuard aGuard( lclMutex::get() ); 147 148 ClientMap::iterator aClientPos; 149 if ( !implLookupClient( _nClient, aClientPos ) ) 150 // already asserted in implLookupClient 151 return; 152 153 // notify the "disposing" event for this client 154 EventObject aDisposalEvent; 155 aDisposalEvent.Source = _rxEventSource; 156 157 // notify the listeners 158 EventListeners* pListeners = aClientPos->second; 159 160 // we do not need the entry in the clients map anymore 161 // (do this before actually notifying, because some client implementations have re-entrance 162 // problems and call into revokeClient while we are notifying from hereing) 163 Clients::get().erase( aClientPos ); 164 165 // now really do the notification 166 pListeners->disposeAndClear( aDisposalEvent ); 167 delete pListeners; 168 169 } 170 171 //--------------------------------------------------------------------- 172 sal_Int32 AccessibleEventNotifier::addEventListener( 173 const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) ) 174 { 175 ::osl::MutexGuard aGuard( lclMutex::get() ); 176 177 ClientMap::iterator aClientPos; 178 if ( !implLookupClient( _nClient, aClientPos ) ) 179 // already asserted in implLookupClient 180 return 0; 181 182 if ( _rxListener.is() ) 183 aClientPos->second->addInterface( _rxListener ); 184 185 return aClientPos->second->getLength(); 186 } 187 188 //--------------------------------------------------------------------- 189 sal_Int32 AccessibleEventNotifier::removeEventListener( 190 const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) ) 191 { 192 ::osl::MutexGuard aGuard( lclMutex::get() ); 193 194 ClientMap::iterator aClientPos; 195 if ( !implLookupClient( _nClient, aClientPos ) ) 196 // already asserted in implLookupClient 197 return 0; 198 199 if ( _rxListener.is() ) 200 aClientPos->second->removeInterface( _rxListener ); 201 202 return aClientPos->second->getLength(); 203 } 204 205 //--------------------------------------------------------------------- 206 Sequence< Reference< XInterface > > AccessibleEventNotifier::getEventListeners( const TClientId _nClient ) SAL_THROW( ( ) ) 207 { 208 Sequence< Reference< XInterface > > aListeners; 209 210 ::osl::MutexGuard aGuard( lclMutex::get() ); 211 212 ClientMap::iterator aClientPos; 213 if ( implLookupClient( _nClient, aClientPos ) ) 214 aListeners = aClientPos->second->getElements(); 215 216 return aListeners; 217 } 218 219 //--------------------------------------------------------------------- 220 void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) ) 221 { 222 Sequence< Reference< XInterface > > aListeners; 223 224 // --- <mutex lock> ------------------------------- 225 { 226 ::osl::MutexGuard aGuard( lclMutex::get() ); 227 228 ClientMap::iterator aClientPos; 229 if ( !implLookupClient( _nClient, aClientPos ) ) 230 // already asserted in implLookupClient 231 return; 232 233 // since we're synchronous, again, we want to notify immediately 234 aListeners = aClientPos->second->getElements(); 235 } 236 // --- </mutex lock> ------------------------------ 237 238 // default handling: loop through all listeners, and notify them 239 const Reference< XInterface >* pListeners = aListeners.getConstArray(); 240 const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength(); 241 while ( pListeners != pListenersEnd ) 242 { 243 try 244 { 245 static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent ); 246 } 247 catch( const Exception& ) 248 { 249 // no assertion, because a broken access remote bridge or something like this 250 // can cause this exception 251 } 252 ++pListeners; 253 } 254 } 255 256 //......................................................................... 257 } // namespace comphelper 258 //......................................................................... 259 260