Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
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/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
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 .
18 : : */
19 : :
20 : : #include <comphelper/accessibleeventnotifier.hxx>
21 : : #include <osl/diagnose.h>
22 : : #include <rtl/instance.hxx>
23 : : #include <comphelper/guarding.hxx>
24 : :
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;
29 : :
30 : : //=====================================================================
31 : : //= AccessibleEventNotifier
32 : : //=====================================================================
33 : : //---------------------------------------------------------------------
34 : : namespace
35 : : {
36 : : struct lclMutex
37 : : : public rtl::Static< ::osl::Mutex, lclMutex > {};
38 : : struct Clients
39 : : : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {};
40 : : }
41 : :
42 : : //.........................................................................
43 : : namespace comphelper
44 : : {
45 : : //.........................................................................
46 : :
47 : : //---------------------------------------------------------------------
48 : 429 : AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId()
49 : : {
50 : 429 : TClientId nBiggestUsedId = 0;
51 : 429 : TClientId nFreeId = 0;
52 : :
53 : : // look through all registered clients until we find a "gap" in the ids
54 : :
55 : : // Note that the following relies on the fact the elements in the map are traveled with
56 : : // ascending keys (aka client ids)
57 : 429 : AccessibleEventNotifier::ClientMap &rClients = Clients::get();
58 [ + - ][ + - ]: 24082 : for ( ClientMap::const_iterator aLookup = rClients.begin();
[ + + ][ + - ]
59 [ + - ]: 12041 : aLookup != rClients.end();
60 : : ++aLookup
61 : : )
62 : : {
63 [ + - ]: 11630 : TClientId nCurrent = aLookup->first;
64 : : OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );
65 : :
66 [ + + ]: 11630 : if ( nCurrent - nBiggestUsedId > 1 )
67 : : { // found a "gap"
68 : 18 : nFreeId = nBiggestUsedId + 1;
69 : 18 : break;
70 : : }
71 : :
72 : 11612 : nBiggestUsedId = nCurrent;
73 : : }
74 : :
75 [ + + ]: 429 : if ( !nFreeId )
76 : 411 : nFreeId = nBiggestUsedId + 1;
77 : :
78 : : OSL_ENSURE( rClients.end() == rClients.find( nFreeId ),
79 : : "AccessibleEventNotifier::generateId: algorithm broken!" );
80 : :
81 : 429 : return nFreeId;
82 : : }
83 : :
84 : : //---------------------------------------------------------------------
85 : 429 : AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( )
86 : : {
87 [ + - ][ + - ]: 429 : ::osl::MutexGuard aGuard( lclMutex::get() );
88 : :
89 : : // generate a new client id
90 [ + - ]: 429 : TClientId nNewClientId = generateId( );
91 : :
92 : : // the event listeners for the new client
93 [ + - ][ + - ]: 429 : 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 ...
98 : :
99 : : // add the client
100 [ + - ][ + - ]: 429 : Clients::get().insert( ClientMap::value_type( nNewClientId, pNewListeners ) );
[ + - ]
101 : :
102 : : // outta here
103 [ + - ]: 429 : return nNewClientId;
104 : : }
105 : :
106 : : //---------------------------------------------------------------------
107 : 1001 : sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos )
108 : : {
109 : : // look up this client
110 : 1001 : AccessibleEventNotifier::ClientMap &rClients = Clients::get();
111 : 1001 : _rPos = rClients.find( _nClient );
112 : : OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );
113 : :
114 [ + - ]: 1001 : return ( rClients.end() != _rPos );
115 : : }
116 : :
117 : : //---------------------------------------------------------------------
118 : 123 : void AccessibleEventNotifier::revokeClient( const TClientId _nClient )
119 : : {
120 [ + - ][ + - ]: 123 : ::osl::MutexGuard aGuard( lclMutex::get() );
121 : :
122 [ + - ]: 123 : ClientMap::iterator aClientPos;
123 [ + - ][ + + ]: 123 : if ( !implLookupClient( _nClient, aClientPos ) )
124 : : // already asserted in implLookupClient
125 : 123 : return;
126 : :
127 : : // remove it from the clients map
128 [ + - ][ + - ]: 119 : delete aClientPos->second;
[ + - ]
129 [ + - ][ + - ]: 123 : Clients::get().erase( aClientPos );
[ + - ][ + + ]
130 : : }
131 : :
132 : : //---------------------------------------------------------------------
133 : 109 : void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient,
134 : : const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) )
135 : : {
136 [ + - ][ + - ]: 109 : ::osl::MutexGuard aGuard( lclMutex::get() );
137 : :
138 [ + - ]: 109 : ClientMap::iterator aClientPos;
139 [ + - ][ - + ]: 109 : if ( !implLookupClient( _nClient, aClientPos ) )
140 : : // already asserted in implLookupClient
141 : 109 : return;
142 : :
143 : : // notify the "disposing" event for this client
144 [ + - ]: 109 : EventObject aDisposalEvent;
145 [ + - ]: 109 : aDisposalEvent.Source = _rxEventSource;
146 : :
147 : : // notify the listeners
148 [ + - ]: 109 : EventListeners* pListeners = aClientPos->second;
149 : :
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 [ + - ][ + - ]: 109 : Clients::get().erase( aClientPos );
154 : :
155 : : // now really do the notification
156 [ + - ]: 109 : pListeners->disposeAndClear( aDisposalEvent );
157 [ + - ][ + - ]: 109 : delete pListeners;
[ + - ][ + - ]
[ + - ]
158 : :
159 : : }
160 : :
161 : : //---------------------------------------------------------------------
162 : 365 : sal_Int32 AccessibleEventNotifier::addEventListener(
163 : : const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
164 : : {
165 [ + - ][ + - ]: 365 : ::osl::MutexGuard aGuard( lclMutex::get() );
166 : :
167 [ + - ]: 365 : ClientMap::iterator aClientPos;
168 [ + - ][ - + ]: 365 : if ( !implLookupClient( _nClient, aClientPos ) )
169 : : // already asserted in implLookupClient
170 : 0 : return 0;
171 : :
172 [ + - ]: 365 : if ( _rxListener.is() )
173 [ + - ][ + - ]: 365 : aClientPos->second->addInterface( _rxListener );
174 : :
175 [ + - ][ + - ]: 365 : return aClientPos->second->getLength();
[ + - ]
176 : : }
177 : :
178 : : //---------------------------------------------------------------------
179 : 72 : sal_Int32 AccessibleEventNotifier::removeEventListener(
180 : : const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
181 : : {
182 [ + - ][ + - ]: 72 : ::osl::MutexGuard aGuard( lclMutex::get() );
183 : :
184 [ + - ]: 72 : ClientMap::iterator aClientPos;
185 [ + - ][ + + ]: 72 : if ( !implLookupClient( _nClient, aClientPos ) )
186 : : // already asserted in implLookupClient
187 : 4 : return 0;
188 : :
189 [ + - ]: 68 : if ( _rxListener.is() )
190 [ + - ][ + - ]: 68 : aClientPos->second->removeInterface( _rxListener );
191 : :
192 [ + - ][ + - ]: 72 : return aClientPos->second->getLength();
[ + - ]
193 : : }
194 : :
195 : : //---------------------------------------------------------------------
196 : 332 : void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) )
197 : : {
198 [ + - ]: 332 : Sequence< Reference< XInterface > > aListeners;
199 : :
200 : : // --- <mutex lock> -------------------------------
201 : : {
202 [ + - ][ + - ]: 332 : ::osl::MutexGuard aGuard( lclMutex::get() );
203 : :
204 [ + - ]: 332 : ClientMap::iterator aClientPos;
205 [ + - ][ - + ]: 332 : if ( !implLookupClient( _nClient, aClientPos ) )
206 : : // already asserted in implLookupClient
207 : 332 : return;
208 : :
209 : : // since we're synchronous, again, we want to notify immediately
210 [ + - ][ + - ]: 332 : aListeners = aClientPos->second->getElements();
[ + - ][ + - ]
[ + - ]
[ + - # # ]
211 : : }
212 : : // --- </mutex lock> ------------------------------
213 : :
214 : : // default handling: loop through all listeners, and notify them
215 : 332 : const Reference< XInterface >* pListeners = aListeners.getConstArray();
216 : 332 : const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
217 [ + + ]: 711 : while ( pListeners != pListenersEnd )
218 : : {
219 : : try
220 : : {
221 [ + - ][ + - ]: 379 : static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent );
222 : : }
223 [ # # ]: 0 : catch( const Exception& )
224 : : {
225 : : // no assertion, because a broken access remote bridge or something like this
226 : : // can cause this exception
227 : : }
228 : 379 : ++pListeners;
229 [ + - ][ + - ]: 332 : }
230 : : }
231 : :
232 : : //.........................................................................
233 : : } // namespace comphelper
234 : : //.........................................................................
235 : :
236 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|