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