/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: WindowsAccessBridgeAdapter.cxx,v $ * * $Revision: 1.5 $ * * last change: $Author: rt $ $Date: 2005-09-07 15:44:58 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ //------------------------------------------------------------------------ // includes //------------------------------------------------------------------------ #include #ifndef _RTL_PROCESS_H_ #include #endif #ifndef _LINK_HXX #include #endif #ifndef _SVAPP_HXX #include #endif #ifndef _SV_WINDOW_HXX #include #endif #include #include #include #ifndef _SV_SYSDATA_HXX #include #endif #ifndef _UNO_CURRENT_CONTEXT_HXX_ #include #endif #ifndef _UNO_ENVIRONMENT_H_ #include #endif #ifndef _UNO_MAPPING_HXX_ #include #endif #ifndef _COM_SUN_STAR_ACCESSIBILITY_ACCESSIBLEROLE_HPP_ #include #endif #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLE_HPP_ #include #endif #ifndef _JVMACCESS_UNOVIRTUALMACHINE_HXX_ #include "jvmaccess/unovirtualmachine.hxx" #endif #ifndef _JVMACCESS_VIRTUALMACHINE_HXX_ #include "jvmaccess/virtualmachine.hxx" #endif #include using namespace ::rtl; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::accessibility; long VCLEventListenerLinkFunc(void * pInst, void * pData); //------------------------------------------------------------------------ // global vatiables //------------------------------------------------------------------------ Link g_aEventListenerLink(NULL, VCLEventListenerLinkFunc); rtl::Reference< jvmaccess::UnoVirtualMachine > g_xUnoVirtualMachine; typelib_InterfaceTypeDescription * g_pTypeDescription = NULL; Mapping g_unoMapping; jclass g_jcWindowsAccessBridgeAdapter = NULL; jmethodID g_jmRegisterTopWindow = 0; jmethodID g_jmRevokeTopWindow = 0; //------------------------------------------------------------------------ // functions //------------------------------------------------------------------------ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { return JNI_VERSION_1_2; } JNIEXPORT jbyteArray JNICALL Java_org_openoffice_accessibility_WindowsAccessBridgeAdapter_getProcessID(JNIEnv *pJNIEnv, jclass clazz) { // Initialize global class and method references g_jcWindowsAccessBridgeAdapter = reinterpret_cast< jclass > (pJNIEnv->NewGlobalRef(clazz)); if (NULL == g_jcWindowsAccessBridgeAdapter) { return 0; /* jni error occured */ } g_jmRegisterTopWindow = pJNIEnv->GetStaticMethodID(clazz, "registerTopWindow", "(ILcom/sun/star/accessibility/XAccessible;)V"); if (0 == g_jmRegisterTopWindow) { return 0; /* jni error occured */ } g_jmRevokeTopWindow = pJNIEnv->GetStaticMethodID(clazz, "revokeTopWindow", "(ILcom/sun/star/accessibility/XAccessible;)V"); if (0 == g_jmRevokeTopWindow) { return 0; /* jni error occured */ } // Use the special protocol of XJavaVM.getJavaVM: If the passed in // process ID has an extra 17th byte of value one, the returned any // contains a pointer to a jvmaccess::UnoVirtualMachine, instead of // the underlying JavaVM pointer: jbyte processID[17]; rtl_getGlobalProcessId(reinterpret_cast (processID)); // #i51265# we need a jvmaccess::UnoVirtualMachine pointer for the // uno_getEnvironment() call later. processID[16] = 1; // Copy the result into a java byte[] and return. jbyteArray jbaProcessID = pJNIEnv->NewByteArray(17); pJNIEnv->SetByteArrayRegion(jbaProcessID, 0, 17, processID); return jbaProcessID; } JNIEXPORT jboolean JNICALL Java_org_openoffice_accessibility_WindowsAccessBridgeAdapter_createMapping(JNIEnv *pJNIEnv, jclass clazz, jlong pointer) { uno_Environment * pJava_environment = NULL; uno_Environment * pUno_environment = NULL; try { // We get a non-refcounted pointer to a jvmaccess::VirtualMachine // from the XJavaVM service (the pointer is guaranteed to be valid // as long as our reference to the XJavaVM service lasts), and // convert the non-refcounted pointer into a refcounted one // immediately: g_xUnoVirtualMachine = reinterpret_cast< jvmaccess::UnoVirtualMachine * >(pointer); if ( g_xUnoVirtualMachine.is() ) { OUString sJava(RTL_CONSTASCII_USTRINGPARAM("java")); uno_getEnvironment(&pJava_environment, sJava.pData, g_xUnoVirtualMachine.get()); OUString sCppu_current_lb_name(RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME)); uno_getEnvironment(&pUno_environment, sCppu_current_lb_name.pData, NULL); if ( pJava_environment && pUno_environment ) { g_unoMapping = Mapping(pUno_environment, pJava_environment); getCppuType((Reference< XAccessible > *) 0).getDescription((typelib_TypeDescription **) & g_pTypeDescription); } if ( pJava_environment ) { // release java environment pJava_environment->release(pJava_environment); pJava_environment = NULL; } if ( pUno_environment ) { // release uno environment pUno_environment->release(pUno_environment); pUno_environment = NULL; } } } catch ( RuntimeException e) { OSL_TRACE("RuntimeException caught while initializing the mapping"); } if ( (0 != g_jmRegisterTopWindow) && (0 != g_jmRevokeTopWindow) ) { ::Application::AddEventListener(g_aEventListenerLink); } return JNI_TRUE; } JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved) { ::Application::RemoveEventListener(g_aEventListenerLink); if ( NULL != g_jcWindowsAccessBridgeAdapter ) { JNIEnv * pJNIEnv; if ( ! jvm->GetEnv((void **) &pJNIEnv, JNI_VERSION_1_2) ) { pJNIEnv->DeleteGlobalRef(g_jcWindowsAccessBridgeAdapter); g_jcWindowsAccessBridgeAdapter = NULL; } } if ( NULL != g_pTypeDescription ) { typelib_typedescription_release( reinterpret_cast< typelib_TypeDescription * > (g_pTypeDescription) ); g_pTypeDescription = NULL; } g_unoMapping.clear(); g_xUnoVirtualMachine.clear(); } HWND GetHWND(Window * pWindow) { const SystemEnvData * pEnvData = pWindow->GetSystemData(); if (pEnvData != NULL) { return pEnvData->hWnd; } return (HWND) -1; } void handleWindowEvent(Window * pWindow, bool bShow) { if ( pWindow && pWindow->IsTopWindow() ) { Reference< XAccessible > xAccessible; // Test for combo box - drop down floating windows first Window * pParentWindow = pWindow->GetParent(); if ( pParentWindow ) { try { // The parent window of a combo box floating window should have the role COMBO_BOX Reference< XAccessible > xParentAccessible(pParentWindow->GetAccessible()); if ( xParentAccessible.is() ) { Reference< XAccessibleContext > xParentAC(xParentAccessible->getAccessibleContext()); if ( xParentAC.is() && (AccessibleRole::COMBO_BOX == xParentAC->getAccessibleRole()) ) { // O.k. - this is a combo box floating window corresponding to the child of role LIST of the parent. // Let's not rely on a specific child order, just search for the child with the role LIST sal_Int32 nCount = xParentAC->getAccessibleChildCount(); for ( sal_Int32 n = 0; (n < nCount) && !xAccessible.is(); n++) { Reference< XAccessible > xChild = xParentAC->getAccessibleChild(n); if ( xChild.is() ) { Reference< XAccessibleContext > xChildAC = xChild->getAccessibleContext(); if ( xChildAC.is() && (AccessibleRole::LIST == xChildAC->getAccessibleRole()) ) { xAccessible = xChild; } } } } } } catch (::com::sun::star::uno::RuntimeException e) { // Ignore show events that throw DisposedExceptions in getAccessibleContext(), // but keep revoking these windows in hide(s). if (bShow) return; } } // We have to rely on the fact that Window::GetAccessible()->getAccessibleContext() returns a valid XAccessibleContext // also for other menus than menubar or toplevel popup window. Otherwise we had to traverse the hierarchy to find the // context object to this menu floater. This makes the call to Window->IsMenuFloatingWindow() obsolete. if ( ! xAccessible.is() ) xAccessible = pWindow->GetAccessible(); if ( xAccessible.is() && g_unoMapping.is() ) { jobject * joXAccessible = reinterpret_cast < jobject * > (g_unoMapping.mapInterface( xAccessible.get(), g_pTypeDescription)); if ( NULL != joXAccessible ) { jvmaccess::VirtualMachine::AttachGuard aGuard(g_xUnoVirtualMachine->getVirtualMachine()); JNIEnv * pJNIEnv = aGuard.getEnvironment(); if ( NULL != pJNIEnv ) { // g_jmRegisterTopWindow and g_jmRevokeTopWindow are ensured to be != 0 - otherwise // the event listener would not have been attached. pJNIEnv->CallStaticVoidMethod(g_jcWindowsAccessBridgeAdapter, (bShow) ? g_jmRegisterTopWindow : g_jmRevokeTopWindow, (jint) GetHWND(pWindow), joXAccessible ); // Clear any exception that might have been occured. if (pJNIEnv->ExceptionCheck()) { pJNIEnv->ExceptionClear(); } } } } } } long VCLEventListenerLinkFunc(void * pInst, void * pData) { ::VclSimpleEvent const * pEvent = (::VclSimpleEvent const *) pData; switch (pEvent->GetId()) { case VCLEVENT_WINDOW_SHOW: handleWindowEvent(((::VclWindowEvent const *) pEvent)->GetWindow(), true); break; case VCLEVENT_WINDOW_HIDE: handleWindowEvent(((::VclWindowEvent const *) pEvent)->GetWindow(), false); break; } return 0; }