1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 //---------------------------------------------------------------------
37 : public rtl::Static
< ::osl::Mutex
, lclMutex
> {};
39 : public rtl::Static
< AccessibleEventNotifier::ClientMap
, Clients
> {};
42 //.........................................................................
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();
63 TClientId nCurrent
= aLookup
->first
;
64 OSL_ENSURE( nCurrent
> nBiggestUsedId
, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );
66 if ( nCurrent
- nBiggestUsedId
> 1 )
68 nFreeId
= nBiggestUsedId
+ 1;
72 nBiggestUsedId
= nCurrent
;
76 nFreeId
= nBiggestUsedId
+ 1;
78 OSL_ENSURE( rClients
.end() == rClients
.find( nFreeId
),
79 "AccessibleEventNotifier::generateId: algorithm broken!" );
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 ...
100 Clients::get().insert( ClientMap::value_type( nNewClientId
, pNewListeners
) );
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
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
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
);
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
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
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
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
237 //.........................................................................
238 } // namespace comphelper
239 //.........................................................................
241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */