1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
25 #include <WindowsAccessBridgeAdapter.h>
28 #include <rtl/process.h>
29 #include <tools/link.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/window.hxx>
33 #include <vcl/sysdata.hxx>
34 #include <uno/current_context.hxx>
35 #include <uno/environment.h>
36 #include <uno/mapping.hxx>
37 #include <com/sun/star/accessibility/AccessibleRole.hpp>
38 #include <com/sun/star/accessibility/XAccessible.hpp>
40 #include "jvmaccess/unovirtualmachine.hxx"
42 #include "jvmaccess/virtualmachine.hxx"
44 #include <osl/diagnose.h>
46 using ::com::sun::star::uno::Mapping
;
47 using ::com::sun::star::uno::Reference
;
48 using ::com::sun::star::uno::RuntimeException
;
49 using namespace ::com::sun::star::accessibility
;
51 long VCLEventListenerLinkFunc(void * pInst
, void * pData
);
53 //------------------------------------------------------------------------
55 //------------------------------------------------------------------------
57 Link
g_aEventListenerLink(NULL
, VCLEventListenerLinkFunc
);
59 rtl::Reference
< jvmaccess::UnoVirtualMachine
> g_xUnoVirtualMachine
;
60 typelib_InterfaceTypeDescription
* g_pTypeDescription
= NULL
;
63 jclass g_jcWindowsAccessBridgeAdapter
= NULL
;
64 jmethodID g_jmRegisterTopWindow
= 0;
65 jmethodID g_jmRevokeTopWindow
= 0;
67 //------------------------------------------------------------------------
69 //------------------------------------------------------------------------
71 SAL_DLLPUBLIC_EXPORT jint JNICALL
JNI_OnLoad(JavaVM
*, void *)
73 return JNI_VERSION_1_2
;
76 SAL_DLLPUBLIC_EXPORT jbyteArray JNICALL
77 Java_org_openoffice_accessibility_WindowsAccessBridgeAdapter_getProcessID(JNIEnv
*pJNIEnv
, jclass clazz
)
79 // Initialize global class and method references
80 g_jcWindowsAccessBridgeAdapter
=
81 static_cast< jclass
> (pJNIEnv
->NewGlobalRef(clazz
));
82 if (NULL
== g_jcWindowsAccessBridgeAdapter
) {
83 return 0; /* jni error occurred */
85 g_jmRegisterTopWindow
=
86 pJNIEnv
->GetStaticMethodID(clazz
, "registerTopWindow", "(ILcom/sun/star/accessibility/XAccessible;)V");
87 if (0 == g_jmRegisterTopWindow
) {
88 return 0; /* jni error occurred */
91 pJNIEnv
->GetStaticMethodID(clazz
, "revokeTopWindow", "(ILcom/sun/star/accessibility/XAccessible;)V");
92 if (0 == g_jmRevokeTopWindow
) {
93 return 0; /* jni error occurred */
96 // Use the special protocol of XJavaVM.getJavaVM: If the passed in
97 // process ID has an extra 17th byte of value one, the returned any
98 // contains a pointer to a jvmaccess::UnoVirtualMachine, instead of
99 // the underlying JavaVM pointer:
101 rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8
*> (processID
));
102 // #i51265# we need a jvmaccess::UnoVirtualMachine pointer for the
103 // uno_getEnvironment() call later.
106 // Copy the result into a java byte[] and return.
107 jbyteArray jbaProcessID
= pJNIEnv
->NewByteArray(17);
108 pJNIEnv
->SetByteArrayRegion(jbaProcessID
, 0, 17, processID
);
112 SAL_DLLPUBLIC_EXPORT jboolean JNICALL
113 Java_org_openoffice_accessibility_WindowsAccessBridgeAdapter_createMapping(JNIEnv
*, jclass
, jlong pointer
)
115 uno_Environment
* pJava_environment
= NULL
;
116 uno_Environment
* pUno_environment
= NULL
;
119 // We get a non-refcounted pointer to a jvmaccess::VirtualMachine
120 // from the XJavaVM service (the pointer is guaranteed to be valid
121 // as long as our reference to the XJavaVM service lasts), and
122 // convert the non-refcounted pointer into a refcounted one
124 g_xUnoVirtualMachine
= reinterpret_cast< jvmaccess::UnoVirtualMachine
* >(pointer
);
126 if ( g_xUnoVirtualMachine
.is() )
128 OUString
sJava(RTL_CONSTASCII_USTRINGPARAM("java"));
129 uno_getEnvironment(&pJava_environment
, sJava
.pData
, g_xUnoVirtualMachine
.get());
131 OUString
sCppu_current_lb_name(RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME
));
132 uno_getEnvironment(&pUno_environment
, sCppu_current_lb_name
.pData
, NULL
);
134 if ( pJava_environment
&& pUno_environment
)
136 g_unoMapping
= Mapping(pUno_environment
, pJava_environment
);
137 getCppuType((::com::sun::star::uno::Reference
< XAccessible
> *) 0).getDescription((typelib_TypeDescription
**) & g_pTypeDescription
);
140 if ( pJava_environment
)
142 // release java environment
143 pJava_environment
->release(pJava_environment
);
144 pJava_environment
= NULL
;
147 if ( pUno_environment
)
149 // release uno environment
150 pUno_environment
->release(pUno_environment
);
151 pUno_environment
= NULL
;
156 catch (const RuntimeException
&)
158 OSL_TRACE("RuntimeException caught while initializing the mapping");
161 if ( (0 != g_jmRegisterTopWindow
) && (0 != g_jmRevokeTopWindow
) )
163 ::Application::AddEventListener(g_aEventListenerLink
);
168 SAL_DLLPUBLIC_EXPORT
void JNICALL
JNI_OnUnload(JavaVM
*jvm
, void *)
170 ::Application::RemoveEventListener(g_aEventListenerLink
);
172 if ( NULL
!= g_jcWindowsAccessBridgeAdapter
)
175 if ( ! jvm
->GetEnv((void **) &pJNIEnv
, JNI_VERSION_1_2
) )
177 pJNIEnv
->DeleteGlobalRef(g_jcWindowsAccessBridgeAdapter
);
178 g_jcWindowsAccessBridgeAdapter
= NULL
;
182 if ( NULL
!= g_pTypeDescription
)
184 typelib_typedescription_release( reinterpret_cast< typelib_TypeDescription
* > (g_pTypeDescription
) );
185 g_pTypeDescription
= NULL
;
188 g_unoMapping
.clear();
189 g_xUnoVirtualMachine
.clear();
192 HWND
GetHWND(Window
* pWindow
)
194 const SystemEnvData
* pEnvData
= pWindow
->GetSystemData();
195 if (pEnvData
!= NULL
)
197 return pEnvData
->hWnd
;
202 void handleWindowEvent(Window
* pWindow
, bool bShow
)
204 if ( pWindow
&& pWindow
->IsTopWindow() )
206 ::com::sun::star::uno::Reference
< XAccessible
> xAccessible
;
208 // Test for combo box - drop down floating windows first
209 Window
* pParentWindow
= pWindow
->GetParent();
215 // The parent window of a combo box floating window should have the role COMBO_BOX
216 ::com::sun::star::uno::Reference
< XAccessible
> xParentAccessible(pParentWindow
->GetAccessible());
217 if ( xParentAccessible
.is() )
219 ::com::sun::star::uno::Reference
< XAccessibleContext
> xParentAC(xParentAccessible
->getAccessibleContext());
220 if ( xParentAC
.is() && (AccessibleRole::COMBO_BOX
== xParentAC
->getAccessibleRole()) )
222 // O.k. - this is a combo box floating window corresponding to the child of role LIST of the parent.
223 // Let's not rely on a specific child order, just search for the child with the role LIST
224 sal_Int32 nCount
= xParentAC
->getAccessibleChildCount();
225 for ( sal_Int32 n
= 0; (n
< nCount
) && !xAccessible
.is(); n
++)
227 ::com::sun::star::uno::Reference
< XAccessible
> xChild
= xParentAC
->getAccessibleChild(n
);
230 ::com::sun::star::uno::Reference
< XAccessibleContext
> xChildAC
= xChild
->getAccessibleContext();
231 if ( xChildAC
.is() && (AccessibleRole::LIST
== xChildAC
->getAccessibleRole()) )
233 xAccessible
= xChild
;
240 catch (const ::com::sun::star::uno::RuntimeException
&)
242 // Ignore show events that throw DisposedExceptions in getAccessibleContext(),
243 // but keep revoking these windows in hide(s).
249 // We have to rely on the fact that Window::GetAccessible()->getAccessibleContext() returns a valid XAccessibleContext
250 // also for other menus than menubar or toplevel popup window. Otherwise we had to traverse the hierarchy to find the
251 // context object to this menu floater. This makes the call to Window->IsMenuFloatingWindow() obsolete.
252 if ( ! xAccessible
.is() )
253 xAccessible
= pWindow
->GetAccessible();
255 if ( xAccessible
.is() && g_unoMapping
.is() )
257 jobject
* joXAccessible
= reinterpret_cast < jobject
* > (g_unoMapping
.mapInterface(
258 xAccessible
.get(), g_pTypeDescription
));
260 if ( NULL
!= joXAccessible
)
262 jvmaccess::VirtualMachine::AttachGuard
aGuard(g_xUnoVirtualMachine
->getVirtualMachine());
263 JNIEnv
* pJNIEnv
= aGuard
.getEnvironment();
265 if ( NULL
!= pJNIEnv
)
267 // g_jmRegisterTopWindow and g_jmRevokeTopWindow are ensured to be != 0 - otherwise
268 // the event listener would not have been attached.
269 pJNIEnv
->CallStaticVoidMethod(g_jcWindowsAccessBridgeAdapter
,
270 (bShow
) ? g_jmRegisterTopWindow
: g_jmRevokeTopWindow
,
271 (jint
) GetHWND(pWindow
), joXAccessible
);
273 // Clear any exception that might have been occurred.
274 if (pJNIEnv
->ExceptionCheck()) {
275 pJNIEnv
->ExceptionClear();
283 long VCLEventListenerLinkFunc(void *, void * pData
)
285 ::VclSimpleEvent
const * pEvent
= (::VclSimpleEvent
const *) pData
;
287 switch (pEvent
->GetId())
289 case VCLEVENT_WINDOW_SHOW
:
290 handleWindowEvent(((::VclWindowEvent
const *) pEvent
)->GetWindow(), true);
292 case VCLEVENT_WINDOW_HIDE
:
293 handleWindowEvent(((::VclWindowEvent
const *) pEvent
)->GetWindow(), false);
300 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */