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_toolkit.hxx"
26 #include <toolkit/helper/accessibilityclient.hxx>
27 #include <toolkit/helper/accessiblefactory.hxx>
28 #include <osl/module.h>
29 #include <osl/diagnose.h>
30 #include <tools/solar.h>
31 
32 // #define UNLOAD_ON_LAST_CLIENT_DYING
33     // this is not recommended currently. If enabled, the implementation will log
34     // the number of active clients, and unload the acc library when the last client
35     // goes away.
36     // Sounds like a good idea, unfortunately, there's no guarantee that all objects
37     // implemented in this library are already dead.
38     // Iow, just because an object implementing an XAccessible (implemented in this lib
39     // here) died, it's not said that everybody released all references to the
40     // XAccessibleContext used by this component, and implemented in the acc lib.
41     // So we cannot really unload the lib.
42     //
43     // Alternatively, if the lib would us own "usage counting", i.e. every component
44     // implemented therein would affect a static ref count, the acc lib could care
45     // for unloading itself.
46 
47 //........................................................................
48 namespace toolkit
49 {
50 //........................................................................
51 
52     using namespace ::com::sun::star::uno;
53     using namespace ::com::sun::star::accessibility;
54 
55     namespace
56     {
57 #ifdef UNLOAD_ON_LAST_CLIENT_DYING
58         static oslInterlockedCount                      s_nAccessibilityClients = 0;
59 #endif // UNLOAD_ON_LAST_CLIENT_DYING
60         static oslModule                                s_hAccessibleImplementationModule = NULL;
61         static GetStandardAccComponentFactory           s_pAccessibleFactoryFunc = NULL;
62         static ::rtl::Reference< IAccessibleFactory >   s_pFactory;
63     }
64 
65     //====================================================================
66 	//= AccessibleDummyFactory
67 	//====================================================================
68     class AccessibleDummyFactory : public IAccessibleFactory
69     {
70     public:
71         AccessibleDummyFactory();
72 
73     protected:
74         virtual ~AccessibleDummyFactory();
75 
76     private:
77         AccessibleDummyFactory( const AccessibleDummyFactory& );            // never implemented
78         AccessibleDummyFactory& operator=( const AccessibleDummyFactory& ); // never implemented
79 
80         oslInterlockedCount m_refCount;
81 
82     public:
83         // IReference
84 	    virtual oslInterlockedCount SAL_CALL acquire();
85 	    virtual oslInterlockedCount SAL_CALL release();
86 
87         // IAccessibleFactory
88         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXButton *)89                 createAccessibleContext( VCLXButton* /*_pXWindow*/ )
90         {
91             return NULL;
92         }
93         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXCheckBox *)94                 createAccessibleContext( VCLXCheckBox* /*_pXWindow*/ )
95         {
96             return NULL;
97         }
98         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXRadioButton *)99                 createAccessibleContext( VCLXRadioButton* /*_pXWindow*/ )
100         {
101             return NULL;
102         }
103         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXListBox *)104                 createAccessibleContext( VCLXListBox* /*_pXWindow*/ )
105         {
106             return NULL;
107         }
108         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXFixedHyperlink *)109                 createAccessibleContext( VCLXFixedHyperlink* /*_pXWindow*/ )
110         {
111             return NULL;
112         }
113         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXFixedText *)114                 createAccessibleContext( VCLXFixedText* /*_pXWindow*/ )
115         {
116             return NULL;
117         }
118         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXScrollBar *)119                 createAccessibleContext( VCLXScrollBar* /*_pXWindow*/ )
120         {
121             return NULL;
122         }
123         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXEdit *)124                 createAccessibleContext( VCLXEdit* /*_pXWindow*/ )
125         {
126             return NULL;
127         }
128         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXComboBox *)129                 createAccessibleContext( VCLXComboBox* /*_pXWindow*/ )
130         {
131             return NULL;
132         }
133         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXToolBox *)134                 createAccessibleContext( VCLXToolBox* /*_pXWindow*/ )
135         {
136             return NULL;
137         }
138         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
createAccessibleContext(VCLXWindow *)139                 createAccessibleContext( VCLXWindow* /*_pXWindow*/ )
140         {
141             return NULL;
142         }
143         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >
createAccessible(Menu *,sal_Bool)144                 createAccessible( Menu* /*_pMenu*/, sal_Bool /*_bIsMenuBar*/ )
145         {
146             return NULL;
147         }
148     };
149 
150 	//--------------------------------------------------------------------
AccessibleDummyFactory()151     AccessibleDummyFactory::AccessibleDummyFactory()
152     {
153     }
154 
155 	//--------------------------------------------------------------------
~AccessibleDummyFactory()156     AccessibleDummyFactory::~AccessibleDummyFactory()
157     {
158     }
159 
160 	//--------------------------------------------------------------------
acquire()161 	oslInterlockedCount SAL_CALL AccessibleDummyFactory::acquire()
162     {
163         return osl_incrementInterlockedCount( &m_refCount );
164     }
165 
166 	//--------------------------------------------------------------------
release()167 	oslInterlockedCount SAL_CALL AccessibleDummyFactory::release()
168     {
169         if ( 0 == osl_decrementInterlockedCount( &m_refCount ) )
170         {
171             delete this;
172             return 0;
173         }
174         return m_refCount;
175     }
176 
177     //====================================================================
178 	//= AccessibilityClient
179 	//====================================================================
180 	//--------------------------------------------------------------------
AccessibilityClient()181     AccessibilityClient::AccessibilityClient()
182         :m_bInitialized( false )
183     {
184     }
185 
186 	//--------------------------------------------------------------------
thisModule()187     extern "C" { static void SAL_CALL thisModule() {} }
188 
ensureInitialized()189     void AccessibilityClient::ensureInitialized()
190     {
191         if ( m_bInitialized )
192             return;
193 
194         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
195 
196 #ifdef UNLOAD_ON_LAST_CLIENT_DYING
197         if ( 1 == osl_incrementInterlockedCount( &s_nAccessibilityClients ) )
198         {   // the first client
199 #endif // UNLOAD_ON_LAST_CLIENT_DYING
200             // load the library implementing the factory
201             if ( !s_pFactory.get() )
202             {
203 			    const ::rtl::OUString sModuleName = ::rtl::OUString::createFromAscii(
204 				    SVLIBRARY( "acc" )
205 			    );
206                 s_hAccessibleImplementationModule = osl_loadModuleRelative( &thisModule, sModuleName.pData, 0 );
207                 if ( s_hAccessibleImplementationModule != NULL )
208                 {
209 				    const ::rtl::OUString sFactoryCreationFunc =
210                         ::rtl::OUString::createFromAscii( "getStandardAccessibleFactory" );
211 				    s_pAccessibleFactoryFunc = (GetStandardAccComponentFactory)
212                         osl_getFunctionSymbol( s_hAccessibleImplementationModule, sFactoryCreationFunc.pData );
213 
214                 }
215                 OSL_ENSURE( s_pAccessibleFactoryFunc, "AccessibilityClient::ensureInitialized: could not load the library, or not retrieve the needed symbol!" );
216 
217                 // get a factory instance
218                 if ( s_pAccessibleFactoryFunc )
219                 {
220                     IAccessibleFactory* pFactory = static_cast< IAccessibleFactory* >( (*s_pAccessibleFactoryFunc)() );
221                     OSL_ENSURE( pFactory, "AccessibilityClient::ensureInitialized: no factory provided by the A11Y lib!" );
222                     if ( pFactory )
223                     {
224                         s_pFactory = pFactory;
225                         pFactory->release();
226                     }
227                 }
228             }
229 
230             if ( !s_pFactory.get() )
231                 // the attempt to load the lib, or to create the factory, failed
232                 // -> fall back to a dummy factory
233                 s_pFactory = new AccessibleDummyFactory;
234 #ifdef UNLOAD_ON_LAST_CLIENT_DYING
235         }
236 #endif
237 
238         m_bInitialized = true;
239     }
240 
241 	//--------------------------------------------------------------------
~AccessibilityClient()242     AccessibilityClient::~AccessibilityClient()
243     {
244         if ( m_bInitialized )
245         {
246             ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
247 
248 #ifdef UNLOAD_ON_LAST_CLIENT_DYING
249             if( 0 == osl_decrementInterlockedCount( &s_nAccessibilityClients ) )
250             {
251                 s_pFactory = NULL;
252                 s_pAccessibleFactoryFunc = NULL;
253                 if ( s_hAccessibleImplementationModule )
254                 {
255                     osl_unloadModule( s_hAccessibleImplementationModule );
256                     s_hAccessibleImplementationModule = NULL;
257                 }
258             }
259 #endif // UNLOAD_ON_LAST_CLIENT_DYING
260         }
261     }
262 
263     //--------------------------------------------------------------------
getFactory()264     IAccessibleFactory& AccessibilityClient::getFactory()
265     {
266         ensureInitialized();
267         OSL_ENSURE( s_pFactory.is(), "AccessibilityClient::getFactory: at least a dummy factory should have been created!" );
268         return *s_pFactory;
269     }
270 
271 //........................................................................
272 }   // namespace toolkit
273 //........................................................................
274