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