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 ::osl::MutexGuard
aGuard( lclMutex::get() );
138 ClientMap::iterator aClientPos
;
139 if ( !implLookupClient( _nClient
, aClientPos
) )
140 // already asserted in implLookupClient
143 // notify the "disposing" event for this client
144 EventObject aDisposalEvent
;
145 aDisposalEvent
.Source
= _rxEventSource
;
147 // notify the listeners
148 EventListeners
* pListeners
= aClientPos
->second
;
150 // we do not need the entry in the clients map anymore
151 // (do this before actually notifying, because some client implementations have re-entrance
152 // problems and call into revokeClient while we are notifying from hereing)
153 Clients::get().erase( aClientPos
);
155 // now really do the notification
156 pListeners
->disposeAndClear( aDisposalEvent
);
161 //---------------------------------------------------------------------
162 sal_Int32
AccessibleEventNotifier::addEventListener(
163 const TClientId _nClient
, const Reference
< XAccessibleEventListener
>& _rxListener
) SAL_THROW( ( ) )
165 ::osl::MutexGuard
aGuard( lclMutex::get() );
167 ClientMap::iterator aClientPos
;
168 if ( !implLookupClient( _nClient
, aClientPos
) )
169 // already asserted in implLookupClient
172 if ( _rxListener
.is() )
173 aClientPos
->second
->addInterface( _rxListener
);
175 return aClientPos
->second
->getLength();
178 //---------------------------------------------------------------------
179 sal_Int32
AccessibleEventNotifier::removeEventListener(
180 const TClientId _nClient
, const Reference
< XAccessibleEventListener
>& _rxListener
) SAL_THROW( ( ) )
182 ::osl::MutexGuard
aGuard( lclMutex::get() );
184 ClientMap::iterator aClientPos
;
185 if ( !implLookupClient( _nClient
, aClientPos
) )
186 // already asserted in implLookupClient
189 if ( _rxListener
.is() )
190 aClientPos
->second
->removeInterface( _rxListener
);
192 return aClientPos
->second
->getLength();
195 //---------------------------------------------------------------------
196 void AccessibleEventNotifier::addEvent( const TClientId _nClient
, const AccessibleEventObject
& _rEvent
) SAL_THROW( ( ) )
198 Sequence
< Reference
< XInterface
> > aListeners
;
200 // --- <mutex lock> -------------------------------
202 ::osl::MutexGuard
aGuard( lclMutex::get() );
204 ClientMap::iterator aClientPos
;
205 if ( !implLookupClient( _nClient
, aClientPos
) )
206 // already asserted in implLookupClient
209 // since we're synchronous, again, we want to notify immediately
210 aListeners
= aClientPos
->second
->getElements();
212 // --- </mutex lock> ------------------------------
214 // default handling: loop through all listeners, and notify them
215 const Reference
< XInterface
>* pListeners
= aListeners
.getConstArray();
216 const Reference
< XInterface
>* pListenersEnd
= pListeners
+ aListeners
.getLength();
217 while ( pListeners
!= pListenersEnd
)
221 static_cast< XAccessibleEventListener
* >( pListeners
->get() )->notifyEvent( _rEvent
);
223 catch( const Exception
& )
225 // no assertion, because a broken access remote bridge or something like this
226 // can cause this exception
232 //.........................................................................
233 } // namespace comphelper
234 //.........................................................................
236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */