1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: WindowsAccessBridgeAdapter.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_accessibility.hxx"
34 //------------------------------------------------------------------------
36 //------------------------------------------------------------------------
38 #include <WindowsAccessBridgeAdapter.h>
40 #include <tools/prewin.h>
42 #include <tools/postwin.h>
43 #include <rtl/process.h>
44 #include <tools/link.hxx>
47 #include <vcl/svapp.hxx>
49 #include <vcl/window.hxx>
50 #include <vcl/sysdata.hxx>
51 #include <uno/current_context.hxx>
52 #include <uno/environment.h>
53 #include <uno/mapping.hxx>
54 #include <com/sun/star/accessibility/AccessibleRole.hpp>
55 #include <com/sun/star/accessibility/XAccessible.hpp>
57 #ifndef _JVMACCESS_UNOVIRTUALMACHINE_HXX_
58 #include "jvmaccess/unovirtualmachine.hxx"
61 #ifndef _JVMACCESS_VIRTUALMACHINE_HXX_
62 #include "jvmaccess/virtualmachine.hxx"
65 #include <osl/diagnose.h>
67 using ::rtl::OUString
;
68 using ::com::sun::star::uno::Mapping
;
69 using ::com::sun::star::uno::Reference
;
70 using ::com::sun::star::uno::RuntimeException
;
71 using namespace ::com::sun::star::accessibility
;
73 long VCLEventListenerLinkFunc(void * pInst
, void * pData
);
75 //------------------------------------------------------------------------
77 //------------------------------------------------------------------------
79 Link
g_aEventListenerLink(NULL
, VCLEventListenerLinkFunc
);
81 rtl::Reference
< jvmaccess::UnoVirtualMachine
> g_xUnoVirtualMachine
;
82 typelib_InterfaceTypeDescription
* g_pTypeDescription
= NULL
;
85 jclass g_jcWindowsAccessBridgeAdapter
= NULL
;
86 jmethodID g_jmRegisterTopWindow
= 0;
87 jmethodID g_jmRevokeTopWindow
= 0;
89 //------------------------------------------------------------------------
91 //------------------------------------------------------------------------
93 JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM
*, void *)
95 return JNI_VERSION_1_2
;
98 JNIEXPORT jbyteArray JNICALL
99 Java_org_openoffice_accessibility_WindowsAccessBridgeAdapter_getProcessID(JNIEnv
*pJNIEnv
, jclass clazz
)
101 // Initialize global class and method references
102 g_jcWindowsAccessBridgeAdapter
=
103 static_cast< jclass
> (pJNIEnv
->NewGlobalRef(clazz
));
104 if (NULL
== g_jcWindowsAccessBridgeAdapter
) {
105 return 0; /* jni error occured */
107 g_jmRegisterTopWindow
=
108 pJNIEnv
->GetStaticMethodID(clazz
, "registerTopWindow", "(ILcom/sun/star/accessibility/XAccessible;)V");
109 if (0 == g_jmRegisterTopWindow
) {
110 return 0; /* jni error occured */
112 g_jmRevokeTopWindow
=
113 pJNIEnv
->GetStaticMethodID(clazz
, "revokeTopWindow", "(ILcom/sun/star/accessibility/XAccessible;)V");
114 if (0 == g_jmRevokeTopWindow
) {
115 return 0; /* jni error occured */
118 // Use the special protocol of XJavaVM.getJavaVM: If the passed in
119 // process ID has an extra 17th byte of value one, the returned any
120 // contains a pointer to a jvmaccess::UnoVirtualMachine, instead of
121 // the underlying JavaVM pointer:
123 rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8
*> (processID
));
124 // #i51265# we need a jvmaccess::UnoVirtualMachine pointer for the
125 // uno_getEnvironment() call later.
128 // Copy the result into a java byte[] and return.
129 jbyteArray jbaProcessID
= pJNIEnv
->NewByteArray(17);
130 pJNIEnv
->SetByteArrayRegion(jbaProcessID
, 0, 17, processID
);
134 JNIEXPORT jboolean JNICALL
135 Java_org_openoffice_accessibility_WindowsAccessBridgeAdapter_createMapping(JNIEnv
*, jclass
, jlong pointer
)
137 uno_Environment
* pJava_environment
= NULL
;
138 uno_Environment
* pUno_environment
= NULL
;
141 // We get a non-refcounted pointer to a jvmaccess::VirtualMachine
142 // from the XJavaVM service (the pointer is guaranteed to be valid
143 // as long as our reference to the XJavaVM service lasts), and
144 // convert the non-refcounted pointer into a refcounted one
146 g_xUnoVirtualMachine
= reinterpret_cast< jvmaccess::UnoVirtualMachine
* >(pointer
);
148 if ( g_xUnoVirtualMachine
.is() )
150 OUString
sJava(RTL_CONSTASCII_USTRINGPARAM("java"));
151 uno_getEnvironment(&pJava_environment
, sJava
.pData
, g_xUnoVirtualMachine
.get());
153 OUString
sCppu_current_lb_name(RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME
));
154 uno_getEnvironment(&pUno_environment
, sCppu_current_lb_name
.pData
, NULL
);
156 if ( pJava_environment
&& pUno_environment
)
158 g_unoMapping
= Mapping(pUno_environment
, pJava_environment
);
159 getCppuType((::com::sun::star::uno::Reference
< XAccessible
> *) 0).getDescription((typelib_TypeDescription
**) & g_pTypeDescription
);
162 if ( pJava_environment
)
164 // release java environment
165 pJava_environment
->release(pJava_environment
);
166 pJava_environment
= NULL
;
169 if ( pUno_environment
)
171 // release uno environment
172 pUno_environment
->release(pUno_environment
);
173 pUno_environment
= NULL
;
178 catch ( RuntimeException e
)
180 OSL_TRACE("RuntimeException caught while initializing the mapping");
183 if ( (0 != g_jmRegisterTopWindow
) && (0 != g_jmRevokeTopWindow
) )
185 ::Application::AddEventListener(g_aEventListenerLink
);
190 JNIEXPORT
void JNICALL
JNI_OnUnload(JavaVM
*jvm
, void *)
192 ::Application::RemoveEventListener(g_aEventListenerLink
);
194 if ( NULL
!= g_jcWindowsAccessBridgeAdapter
)
197 if ( ! jvm
->GetEnv((void **) &pJNIEnv
, JNI_VERSION_1_2
) )
199 pJNIEnv
->DeleteGlobalRef(g_jcWindowsAccessBridgeAdapter
);
200 g_jcWindowsAccessBridgeAdapter
= NULL
;
204 if ( NULL
!= g_pTypeDescription
)
206 typelib_typedescription_release( reinterpret_cast< typelib_TypeDescription
* > (g_pTypeDescription
) );
207 g_pTypeDescription
= NULL
;
210 g_unoMapping
.clear();
211 g_xUnoVirtualMachine
.clear();
214 HWND
GetHWND(Window
* pWindow
)
216 const SystemEnvData
* pEnvData
= pWindow
->GetSystemData();
217 if (pEnvData
!= NULL
)
219 return pEnvData
->hWnd
;
224 void handleWindowEvent(Window
* pWindow
, bool bShow
)
226 if ( pWindow
&& pWindow
->IsTopWindow() )
228 ::com::sun::star::uno::Reference
< XAccessible
> xAccessible
;
230 // Test for combo box - drop down floating windows first
231 Window
* pParentWindow
= pWindow
->GetParent();
237 // The parent window of a combo box floating window should have the role COMBO_BOX
238 ::com::sun::star::uno::Reference
< XAccessible
> xParentAccessible(pParentWindow
->GetAccessible());
239 if ( xParentAccessible
.is() )
241 ::com::sun::star::uno::Reference
< XAccessibleContext
> xParentAC(xParentAccessible
->getAccessibleContext());
242 if ( xParentAC
.is() && (AccessibleRole::COMBO_BOX
== xParentAC
->getAccessibleRole()) )
244 // O.k. - this is a combo box floating window corresponding to the child of role LIST of the parent.
245 // Let's not rely on a specific child order, just search for the child with the role LIST
246 sal_Int32 nCount
= xParentAC
->getAccessibleChildCount();
247 for ( sal_Int32 n
= 0; (n
< nCount
) && !xAccessible
.is(); n
++)
249 ::com::sun::star::uno::Reference
< XAccessible
> xChild
= xParentAC
->getAccessibleChild(n
);
252 ::com::sun::star::uno::Reference
< XAccessibleContext
> xChildAC
= xChild
->getAccessibleContext();
253 if ( xChildAC
.is() && (AccessibleRole::LIST
== xChildAC
->getAccessibleRole()) )
255 xAccessible
= xChild
;
262 catch (::com::sun::star::uno::RuntimeException e
)
264 // Ignore show events that throw DisposedExceptions in getAccessibleContext(),
265 // but keep revoking these windows in hide(s).
271 // We have to rely on the fact that Window::GetAccessible()->getAccessibleContext() returns a valid XAccessibleContext
272 // also for other menus than menubar or toplevel popup window. Otherwise we had to traverse the hierarchy to find the
273 // context object to this menu floater. This makes the call to Window->IsMenuFloatingWindow() obsolete.
274 if ( ! xAccessible
.is() )
275 xAccessible
= pWindow
->GetAccessible();
277 if ( xAccessible
.is() && g_unoMapping
.is() )
279 jobject
* joXAccessible
= reinterpret_cast < jobject
* > (g_unoMapping
.mapInterface(
280 xAccessible
.get(), g_pTypeDescription
));
282 if ( NULL
!= joXAccessible
)
284 jvmaccess::VirtualMachine::AttachGuard
aGuard(g_xUnoVirtualMachine
->getVirtualMachine());
285 JNIEnv
* pJNIEnv
= aGuard
.getEnvironment();
287 if ( NULL
!= pJNIEnv
)
289 // g_jmRegisterTopWindow and g_jmRevokeTopWindow are ensured to be != 0 - otherwise
290 // the event listener would not have been attached.
291 pJNIEnv
->CallStaticVoidMethod(g_jcWindowsAccessBridgeAdapter
,
292 (bShow
) ? g_jmRegisterTopWindow
: g_jmRevokeTopWindow
,
293 (jint
) GetHWND(pWindow
), joXAccessible
);
295 // Clear any exception that might have been occured.
296 if (pJNIEnv
->ExceptionCheck()) {
297 pJNIEnv
->ExceptionClear();
305 long VCLEventListenerLinkFunc(void *, void * pData
)
307 ::VclSimpleEvent
const * pEvent
= (::VclSimpleEvent
const *) pData
;
309 switch (pEvent
->GetId())
311 case VCLEVENT_WINDOW_SHOW
:
312 handleWindowEvent(((::VclWindowEvent
const *) pEvent
)->GetWindow(), true);
314 case VCLEVENT_WINDOW_HIDE
:
315 handleWindowEvent(((::VclWindowEvent
const *) pEvent
)->GetWindow(), false);