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