/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include "vcl/svapp.hxx" #include "vcl/window.hxx" #include "vcl/toolbox.hxx" #include "vcl/menu.hxx" #include "aqua/aqua11yfocustracker.hxx" #include "documentfocuslistener.hxx" #include #include #include #include #include using namespace ::com::sun::star::accessibility; using namespace ::com::sun::star::uno; //------------------------------------------------------------------------------ static inline Window * getWindow(const ::VclSimpleEvent *pEvent) { return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow(); } //------------------------------------------------------------------------------ // callback function for Application::addEventListener long AquaA11yFocusTracker::WindowEventHandler(AquaA11yFocusTracker *pFocusTracker, ::VclSimpleEvent const *pEvent) { switch (pEvent->GetId()) { case VCLEVENT_WINDOW_PAINT: pFocusTracker-> toolbox_open_floater( getWindow(pEvent) ); break; case VCLEVENT_WINDOW_GETFOCUS: pFocusTracker->window_got_focus( getWindow(pEvent) ); break; case VCLEVENT_OBJECT_DYING: pFocusTracker->m_aDocumentWindowList.erase( getWindow(pEvent) ); // intentional pass through .. case VCLEVENT_TOOLBOX_HIGHLIGHTOFF: pFocusTracker->toolbox_highlight_off( getWindow(pEvent) ); break; case VCLEVENT_TOOLBOX_HIGHLIGHT: pFocusTracker->toolbox_highlight_on( getWindow(pEvent) ); break; case VCLEVENT_TABPAGE_ACTIVATE: pFocusTracker->tabpage_activated( getWindow(pEvent) ); break; case VCLEVENT_MENU_HIGHLIGHT: pFocusTracker->menu_highlighted( static_cast < const VclMenuEvent * > (pEvent) ); break; default: break; }; return 0; } //------------------------------------------------------------------------------ AquaA11yFocusTracker::AquaA11yFocusTracker() : m_aWindowEventLink(this, (PSTUB) WindowEventHandler), m_xDocumentFocusListener(new DocumentFocusListener(*this)) { Application::AddEventListener(m_aWindowEventLink); window_got_focus(Application::GetFocusWindow()); } //------------------------------------------------------------------------------ void AquaA11yFocusTracker::setFocusedObject(const Reference< XAccessible >& xAccessible) { if( xAccessible != m_xFocusedObject ) { m_xFocusedObject = xAccessible; if( m_aFocusListener.is() ) m_aFocusListener->focusedObjectChanged(xAccessible); } } //------------------------------------------------------------------------------ void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox) { Reference< XAccessible > xAccessible( pToolBox->GetAccessible() ); if( xAccessible.is() ) { Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext()); if( xContext.is() ) { sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() ); if( nPos != TOOLBOX_ITEM_NOTFOUND ) setFocusedObject( xContext->getAccessibleChild( nPos ) ); } } } //------------------------------------------------------------------------------ void AquaA11yFocusTracker::toolbox_open_floater(Window *pWindow) { bool bToolboxFound = false; bool bFloatingWindowFound = false; Window * pFloatingWindow = NULL; while ( pWindow != NULL ) { if ( pWindow->GetType() == WINDOW_TOOLBOX ) { bToolboxFound = true; } else if ( pWindow->GetType() == WINDOW_FLOATINGWINDOW ) { bFloatingWindowFound = true; pFloatingWindow = pWindow; } pWindow = pWindow->GetParent(); } if ( bToolboxFound && bFloatingWindowFound ) { Reference < XAccessible > rxAccessible = pFloatingWindow -> GetAccessible(); if ( ! rxAccessible.is() ) { return; } Reference < XAccessibleContext > rxContext = rxAccessible -> getAccessibleContext(); if ( ! rxContext.is() ) { return; } if ( rxContext -> getAccessibleChildCount() > 0 ) { Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 ); if ( ! rxAccessibleChild.is() ) { return; } setFocusedObject ( rxAccessibleChild ); } } } //------------------------------------------------------------------------------ void AquaA11yFocusTracker::toolbox_highlight_on(Window *pWindow) { // Make sure either the toolbox or its parent toolbox has the focus if ( ! pWindow->HasFocus() ) { ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() ); if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() ) return; } notify_toolbox_item_focus(static_cast (pWindow)); } //------------------------------------------------------------------------------ void AquaA11yFocusTracker::toolbox_highlight_off(Window *pWindow) { ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() ); // Notify when leaving sub toolboxes if( pToolBoxParent && pToolBoxParent->HasFocus() ) notify_toolbox_item_focus( pToolBoxParent ); } //------------------------------------------------------------------------------ void AquaA11yFocusTracker::tabpage_activated(Window *pWindow) { Reference< XAccessible > xAccessible( pWindow->GetAccessible() ); if( xAccessible.is() ) { Reference< XAccessibleSelection > xSelection(xAccessible->getAccessibleContext(), UNO_QUERY); if( xSelection.is() ) setFocusedObject( xSelection->getSelectedAccessibleChild(0) ); } } //------------------------------------------------------------------------------ void AquaA11yFocusTracker::menu_highlighted(const VclMenuEvent *pEvent) { Menu * pMenu = pEvent->GetMenu(); if( pMenu ) { Reference< XAccessible > xAccessible( pMenu->GetAccessible() ); if( xAccessible.is() ) setFocusedObject( xAccessible ); } } //------------------------------------------------------------------------------ void AquaA11yFocusTracker::window_got_focus(Window *pWindow) { // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW ) return; // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT if( pWindow->GetType() == WINDOW_TOOLBOX ) return; if( pWindow->GetType() == WINDOW_TABCONTROL ) { tabpage_activated( pWindow ); return; } Reference< XAccessible > xAccessible(pWindow->GetAccessible()); if( ! xAccessible.is() ) return; Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext(); if( ! xContext.is() ) return; Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet(); if( ! xStateSet.is() ) return; /* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we * need to add listeners to the children instead of re-using the tabpage stuff */ if( xStateSet->contains(AccessibleStateType::FOCUSED) && (pWindow->GetType() != WINDOW_TREELISTBOX) ) { setFocusedObject( xAccessible ); } else { if( m_aDocumentWindowList.find(pWindow) == m_aDocumentWindowList.end() ) { m_aDocumentWindowList.insert(pWindow); m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet); } #ifdef ENABLE_TRACING else fprintf(stderr, "Window %p already in the list\n", pWindow ); #endif } }