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