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_accessibility.hxx" 26 27 //------------------------------------------------------------------------ 28 // includes 29 //------------------------------------------------------------------------ 30 31 #include <WindowsAccessBridgeAdapter.h> 32 33 #include <tools/prewin.h> 34 #include <wtypes.h> 35 #include <tools/postwin.h> 36 #include <rtl/process.h> 37 #include <tools/link.hxx> 38 39 #ifndef _SVAPP_HXX 40 #include <vcl/svapp.hxx> 41 #endif 42 #include <vcl/window.hxx> 43 #include <vcl/sysdata.hxx> 44 #include <uno/current_context.hxx> 45 #include <uno/environment.h> 46 #include <uno/mapping.hxx> 47 #include <com/sun/star/accessibility/AccessibleRole.hpp> 48 #include <com/sun/star/accessibility/XAccessible.hpp> 49 50 #ifndef _JVMACCESS_UNOVIRTUALMACHINE_HXX_ 51 #include "jvmaccess/unovirtualmachine.hxx" 52 #endif 53 54 #ifndef _JVMACCESS_VIRTUALMACHINE_HXX_ 55 #include "jvmaccess/virtualmachine.hxx" 56 #endif 57 58 #include <osl/diagnose.h> 59 60 using ::rtl::OUString; 61 using ::com::sun::star::uno::Mapping; 62 using ::com::sun::star::uno::Reference; 63 using ::com::sun::star::uno::RuntimeException; 64 using namespace ::com::sun::star::accessibility; 65 66 long VCLEventListenerLinkFunc(void * pInst, void * pData); 67 68 //------------------------------------------------------------------------ 69 // global vatiables 70 //------------------------------------------------------------------------ 71 72 Link g_aEventListenerLink(NULL, VCLEventListenerLinkFunc); 73 74 rtl::Reference< jvmaccess::UnoVirtualMachine > g_xUnoVirtualMachine; 75 typelib_InterfaceTypeDescription * g_pTypeDescription = NULL; 76 Mapping g_unoMapping; 77 78 jclass g_jcWindowsAccessBridgeAdapter = NULL; 79 jmethodID g_jmRegisterTopWindow = 0; 80 jmethodID g_jmRevokeTopWindow = 0; 81 82 //------------------------------------------------------------------------ 83 // functions 84 //------------------------------------------------------------------------ 85 86 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *, void *) 87 { 88 return JNI_VERSION_1_2; 89 } 90 91 JNIEXPORT jbyteArray JNICALL 92 Java_org_openoffice_accessibility_WindowsAccessBridgeAdapter_getProcessID(JNIEnv *pJNIEnv, jclass clazz) 93 { 94 // Initialize global class and method references 95 g_jcWindowsAccessBridgeAdapter = 96 static_cast< jclass > (pJNIEnv->NewGlobalRef(clazz)); 97 if (NULL == g_jcWindowsAccessBridgeAdapter) { 98 return 0; /* jni error occured */ 99 } 100 g_jmRegisterTopWindow = 101 pJNIEnv->GetStaticMethodID(clazz, "registerTopWindow", "(ILcom/sun/star/accessibility/XAccessible;)V"); 102 if (0 == g_jmRegisterTopWindow) { 103 return 0; /* jni error occured */ 104 } 105 g_jmRevokeTopWindow = 106 pJNIEnv->GetStaticMethodID(clazz, "revokeTopWindow", "(ILcom/sun/star/accessibility/XAccessible;)V"); 107 if (0 == g_jmRevokeTopWindow) { 108 return 0; /* jni error occured */ 109 } 110 111 // Use the special protocol of XJavaVM.getJavaVM: If the passed in 112 // process ID has an extra 17th byte of value one, the returned any 113 // contains a pointer to a jvmaccess::UnoVirtualMachine, instead of 114 // the underlying JavaVM pointer: 115 jbyte processID[17]; 116 rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8 *> (processID)); 117 // #i51265# we need a jvmaccess::UnoVirtualMachine pointer for the 118 // uno_getEnvironment() call later. 119 processID[16] = 1; 120 121 // Copy the result into a java byte[] and return. 122 jbyteArray jbaProcessID = pJNIEnv->NewByteArray(17); 123 pJNIEnv->SetByteArrayRegion(jbaProcessID, 0, 17, processID); 124 return jbaProcessID; 125 } 126 127 JNIEXPORT jboolean JNICALL 128 Java_org_openoffice_accessibility_WindowsAccessBridgeAdapter_createMapping(JNIEnv *, jclass, jlong pointer) 129 { 130 uno_Environment * pJava_environment = NULL; 131 uno_Environment * pUno_environment = NULL; 132 133 try { 134 // We get a non-refcounted pointer to a jvmaccess::VirtualMachine 135 // from the XJavaVM service (the pointer is guaranteed to be valid 136 // as long as our reference to the XJavaVM service lasts), and 137 // convert the non-refcounted pointer into a refcounted one 138 // immediately: 139 g_xUnoVirtualMachine = reinterpret_cast< jvmaccess::UnoVirtualMachine * >(pointer); 140 141 if ( g_xUnoVirtualMachine.is() ) 142 { 143 OUString sJava(RTL_CONSTASCII_USTRINGPARAM("java")); 144 uno_getEnvironment(&pJava_environment, sJava.pData, g_xUnoVirtualMachine.get()); 145 146 OUString sCppu_current_lb_name(RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME)); 147 uno_getEnvironment(&pUno_environment, sCppu_current_lb_name.pData, NULL); 148 149 if ( pJava_environment && pUno_environment ) 150 { 151 g_unoMapping = Mapping(pUno_environment, pJava_environment); 152 getCppuType((::com::sun::star::uno::Reference< XAccessible > *) 0).getDescription((typelib_TypeDescription **) & g_pTypeDescription); 153 } 154 155 if ( pJava_environment ) 156 { 157 // release java environment 158 pJava_environment->release(pJava_environment); 159 pJava_environment = NULL; 160 } 161 162 if ( pUno_environment ) 163 { 164 // release uno environment 165 pUno_environment->release(pUno_environment); 166 pUno_environment = NULL; 167 } 168 } 169 } 170 171 catch ( RuntimeException e) 172 { 173 OSL_TRACE("RuntimeException caught while initializing the mapping"); 174 } 175 176 if ( (0 != g_jmRegisterTopWindow) && (0 != g_jmRevokeTopWindow) ) 177 { 178 ::Application::AddEventListener(g_aEventListenerLink); 179 } 180 return JNI_TRUE; 181 } 182 183 JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *) 184 { 185 ::Application::RemoveEventListener(g_aEventListenerLink); 186 187 if ( NULL != g_jcWindowsAccessBridgeAdapter ) 188 { 189 JNIEnv * pJNIEnv; 190 if ( ! jvm->GetEnv((void **) &pJNIEnv, JNI_VERSION_1_2) ) 191 { 192 pJNIEnv->DeleteGlobalRef(g_jcWindowsAccessBridgeAdapter); 193 g_jcWindowsAccessBridgeAdapter = NULL; 194 } 195 } 196 197 if ( NULL != g_pTypeDescription ) 198 { 199 typelib_typedescription_release( reinterpret_cast< typelib_TypeDescription * > (g_pTypeDescription) ); 200 g_pTypeDescription = NULL; 201 } 202 203 g_unoMapping.clear(); 204 g_xUnoVirtualMachine.clear(); 205 } 206 207 HWND GetHWND(Window * pWindow) 208 { 209 const SystemEnvData * pEnvData = pWindow->GetSystemData(); 210 if (pEnvData != NULL) 211 { 212 return pEnvData->hWnd; 213 } 214 return (HWND) -1; 215 } 216 217 void handleWindowEvent(Window * pWindow, bool bShow) 218 { 219 if ( pWindow && pWindow->IsTopWindow() ) 220 { 221 ::com::sun::star::uno::Reference< XAccessible > xAccessible; 222 223 // Test for combo box - drop down floating windows first 224 Window * pParentWindow = pWindow->GetParent(); 225 226 if ( pParentWindow ) 227 { 228 try 229 { 230 // The parent window of a combo box floating window should have the role COMBO_BOX 231 ::com::sun::star::uno::Reference< XAccessible > xParentAccessible(pParentWindow->GetAccessible()); 232 if ( xParentAccessible.is() ) 233 { 234 ::com::sun::star::uno::Reference< XAccessibleContext > xParentAC(xParentAccessible->getAccessibleContext()); 235 if ( xParentAC.is() && (AccessibleRole::COMBO_BOX == xParentAC->getAccessibleRole()) ) 236 { 237 // O.k. - this is a combo box floating window corresponding to the child of role LIST of the parent. 238 // Let's not rely on a specific child order, just search for the child with the role LIST 239 sal_Int32 nCount = xParentAC->getAccessibleChildCount(); 240 for ( sal_Int32 n = 0; (n < nCount) && !xAccessible.is(); n++) 241 { 242 ::com::sun::star::uno::Reference< XAccessible > xChild = xParentAC->getAccessibleChild(n); 243 if ( xChild.is() ) 244 { 245 ::com::sun::star::uno::Reference< XAccessibleContext > xChildAC = xChild->getAccessibleContext(); 246 if ( xChildAC.is() && (AccessibleRole::LIST == xChildAC->getAccessibleRole()) ) 247 { 248 xAccessible = xChild; 249 } 250 } 251 } 252 } 253 } 254 } 255 catch (::com::sun::star::uno::RuntimeException e) 256 { 257 // Ignore show events that throw DisposedExceptions in getAccessibleContext(), 258 // but keep revoking these windows in hide(s). 259 if (bShow) 260 return; 261 } 262 } 263 264 // We have to rely on the fact that Window::GetAccessible()->getAccessibleContext() returns a valid XAccessibleContext 265 // also for other menus than menubar or toplevel popup window. Otherwise we had to traverse the hierarchy to find the 266 // context object to this menu floater. This makes the call to Window->IsMenuFloatingWindow() obsolete. 267 if ( ! xAccessible.is() ) 268 xAccessible = pWindow->GetAccessible(); 269 270 if ( xAccessible.is() && g_unoMapping.is() ) 271 { 272 jobject * joXAccessible = reinterpret_cast < jobject * > (g_unoMapping.mapInterface( 273 xAccessible.get(), g_pTypeDescription)); 274 275 if ( NULL != joXAccessible ) 276 { 277 jvmaccess::VirtualMachine::AttachGuard aGuard(g_xUnoVirtualMachine->getVirtualMachine()); 278 JNIEnv * pJNIEnv = aGuard.getEnvironment(); 279 280 if ( NULL != pJNIEnv ) 281 { 282 // g_jmRegisterTopWindow and g_jmRevokeTopWindow are ensured to be != 0 - otherwise 283 // the event listener would not have been attached. 284 pJNIEnv->CallStaticVoidMethod(g_jcWindowsAccessBridgeAdapter, 285 (bShow) ? g_jmRegisterTopWindow : g_jmRevokeTopWindow, 286 (jint) GetHWND(pWindow), joXAccessible ); 287 288 // Clear any exception that might have been occured. 289 if (pJNIEnv->ExceptionCheck()) { 290 pJNIEnv->ExceptionClear(); 291 } 292 } 293 } 294 } 295 } 296 } 297 298 long VCLEventListenerLinkFunc(void *, void * pData) 299 { 300 ::VclSimpleEvent const * pEvent = (::VclSimpleEvent const *) pData; 301 302 switch (pEvent->GetId()) 303 { 304 case VCLEVENT_WINDOW_SHOW: 305 handleWindowEvent(((::VclWindowEvent const *) pEvent)->GetWindow(), true); 306 break; 307 case VCLEVENT_WINDOW_HIDE: 308 handleWindowEvent(((::VclWindowEvent const *) pEvent)->GetWindow(), false); 309 break; 310 } 311 312 return 0; 313 } 314