1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_toolkit.hxx"
30 #include <toolkit/helper/accessibilityclient.hxx>
31 #include <toolkit/helper/accessiblefactory.hxx>
32 #include <osl/module.h>
33 #include <osl/diagnose.h>
34 #include <tools/solar.h>
35 
36 // #define UNLOAD_ON_LAST_CLIENT_DYING
37     // this is not recommended currently. If enabled, the implementation will log
38     // the number of active clients, and unload the acc library when the last client
39     // goes away.
40     // Sounds like a good idea, unfortunately, there's no guarantee that all objects
41     // implemented in this library are already dead.
42     // Iow, just because an object implementing an XAccessible (implemented in this lib
43     // here) died, it's not said that everybody released all references to the
44     // XAccessibleContext used by this component, and implemented in the acc lib.
45     // So we cannot really unload the lib.
46     //
47     // Alternatively, if the lib would us own "usage counting", i.e. every component
48     // implemented therein would affect a static ref count, the acc lib could care
49     // for unloading itself.
50 
51 //........................................................................
52 namespace toolkit
53 {
54 //........................................................................
55 
56     using namespace ::com::sun::star::uno;
57     using namespace ::com::sun::star::accessibility;
58 
59     namespace
60     {
61 #ifdef UNLOAD_ON_LAST_CLIENT_DYING
62         static oslInterlockedCount                      s_nAccessibilityClients = 0;
63 #endif // UNLOAD_ON_LAST_CLIENT_DYING
64         static oslModule                                s_hAccessibleImplementationModule = NULL;
65         static GetStandardAccComponentFactory           s_pAccessibleFactoryFunc = NULL;
66         static ::rtl::Reference< IAccessibleFactory >   s_pFactory;
67     }
68 
69     //====================================================================
70 	//= AccessibleDummyFactory
71 	//====================================================================
72     class AccessibleDummyFactory : public IAccessibleFactory
73     {
74     public:
75         AccessibleDummyFactory();
76 
77     protected:
78         virtual ~AccessibleDummyFactory();
79 
80     private:
81         AccessibleDummyFactory( const AccessibleDummyFactory& );            // never implemented
82         AccessibleDummyFactory& operator=( const AccessibleDummyFactory& ); // never implemented
83 
84         oslInterlockedCount m_refCount;
85 
86     public:
87         // IReference
88 	    virtual oslInterlockedCount SAL_CALL acquire();
89 	    virtual oslInterlockedCount SAL_CALL release();
90 
91         // IAccessibleFactory
92         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
93                 createAccessibleContext( VCLXButton* /*_pXWindow*/ )
94         {
95             return NULL;
96         }
97         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
98                 createAccessibleContext( VCLXCheckBox* /*_pXWindow*/ )
99         {
100             return NULL;
101         }
102         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
103                 createAccessibleContext( VCLXRadioButton* /*_pXWindow*/ )
104         {
105             return NULL;
106         }
107         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
108                 createAccessibleContext( VCLXListBox* /*_pXWindow*/ )
109         {
110             return NULL;
111         }
112         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
113                 createAccessibleContext( VCLXFixedHyperlink* /*_pXWindow*/ )
114         {
115             return NULL;
116         }
117         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
118                 createAccessibleContext( VCLXFixedText* /*_pXWindow*/ )
119         {
120             return NULL;
121         }
122         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
123                 createAccessibleContext( VCLXScrollBar* /*_pXWindow*/ )
124         {
125             return NULL;
126         }
127         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
128                 createAccessibleContext( VCLXEdit* /*_pXWindow*/ )
129         {
130             return NULL;
131         }
132         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
133                 createAccessibleContext( VCLXComboBox* /*_pXWindow*/ )
134         {
135             return NULL;
136         }
137         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
138                 createAccessibleContext( VCLXToolBox* /*_pXWindow*/ )
139         {
140             return NULL;
141         }
142         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext >
143                 createAccessibleContext( VCLXWindow* /*_pXWindow*/ )
144         {
145             return NULL;
146         }
147         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >
148                 createAccessible( Menu* /*_pMenu*/, sal_Bool /*_bIsMenuBar*/ )
149         {
150             return NULL;
151         }
152     };
153 
154 	//--------------------------------------------------------------------
155     AccessibleDummyFactory::AccessibleDummyFactory()
156     {
157     }
158 
159 	//--------------------------------------------------------------------
160     AccessibleDummyFactory::~AccessibleDummyFactory()
161     {
162     }
163 
164 	//--------------------------------------------------------------------
165 	oslInterlockedCount SAL_CALL AccessibleDummyFactory::acquire()
166     {
167         return osl_incrementInterlockedCount( &m_refCount );
168     }
169 
170 	//--------------------------------------------------------------------
171 	oslInterlockedCount SAL_CALL AccessibleDummyFactory::release()
172     {
173         if ( 0 == osl_decrementInterlockedCount( &m_refCount ) )
174         {
175             delete this;
176             return 0;
177         }
178         return m_refCount;
179     }
180 
181     //====================================================================
182 	//= AccessibilityClient
183 	//====================================================================
184 	//--------------------------------------------------------------------
185     AccessibilityClient::AccessibilityClient()
186         :m_bInitialized( false )
187     {
188     }
189 
190 	//--------------------------------------------------------------------
191     extern "C" { static void SAL_CALL thisModule() {} }
192 
193     void AccessibilityClient::ensureInitialized()
194     {
195         if ( m_bInitialized )
196             return;
197 
198         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
199 
200 #ifdef UNLOAD_ON_LAST_CLIENT_DYING
201         if ( 1 == osl_incrementInterlockedCount( &s_nAccessibilityClients ) )
202         {   // the first client
203 #endif // UNLOAD_ON_LAST_CLIENT_DYING
204             // load the library implementing the factory
205             if ( !s_pFactory.get() )
206             {
207 			    const ::rtl::OUString sModuleName = ::rtl::OUString::createFromAscii(
208 				    SVLIBRARY( "acc" )
209 			    );
210                 s_hAccessibleImplementationModule = osl_loadModuleRelative( &thisModule, sModuleName.pData, 0 );
211                 if ( s_hAccessibleImplementationModule != NULL )
212                 {
213 				    const ::rtl::OUString sFactoryCreationFunc =
214                         ::rtl::OUString::createFromAscii( "getStandardAccessibleFactory" );
215 				    s_pAccessibleFactoryFunc = (GetStandardAccComponentFactory)
216                         osl_getFunctionSymbol( s_hAccessibleImplementationModule, sFactoryCreationFunc.pData );
217 
218                 }
219                 OSL_ENSURE( s_pAccessibleFactoryFunc, "AccessibilityClient::ensureInitialized: could not load the library, or not retrieve the needed symbol!" );
220 
221                 // get a factory instance
222                 if ( s_pAccessibleFactoryFunc )
223                 {
224                     IAccessibleFactory* pFactory = static_cast< IAccessibleFactory* >( (*s_pAccessibleFactoryFunc)() );
225                     OSL_ENSURE( pFactory, "AccessibilityClient::ensureInitialized: no factory provided by the A11Y lib!" );
226                     if ( pFactory )
227                     {
228                         s_pFactory = pFactory;
229                         pFactory->release();
230                     }
231                 }
232             }
233 
234             if ( !s_pFactory.get() )
235                 // the attempt to load the lib, or to create the factory, failed
236                 // -> fall back to a dummy factory
237                 s_pFactory = new AccessibleDummyFactory;
238 #ifdef UNLOAD_ON_LAST_CLIENT_DYING
239         }
240 #endif
241 
242         m_bInitialized = true;
243     }
244 
245 	//--------------------------------------------------------------------
246     AccessibilityClient::~AccessibilityClient()
247     {
248         if ( m_bInitialized )
249         {
250             ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
251 
252 #ifdef UNLOAD_ON_LAST_CLIENT_DYING
253             if( 0 == osl_decrementInterlockedCount( &s_nAccessibilityClients ) )
254             {
255                 s_pFactory = NULL;
256                 s_pAccessibleFactoryFunc = NULL;
257                 if ( s_hAccessibleImplementationModule )
258                 {
259                     osl_unloadModule( s_hAccessibleImplementationModule );
260                     s_hAccessibleImplementationModule = NULL;
261                 }
262             }
263 #endif // UNLOAD_ON_LAST_CLIENT_DYING
264         }
265     }
266 
267     //--------------------------------------------------------------------
268     IAccessibleFactory& AccessibilityClient::getFactory()
269     {
270         ensureInitialized();
271         OSL_ENSURE( s_pFactory.is(), "AccessibilityClient::getFactory: at least a dummy factory should have been created!" );
272         return *s_pFactory;
273     }
274 
275 //........................................................................
276 }   // namespace toolkit
277 //........................................................................
278