Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / osx / a11yfocustracker.cxx
blob47dd65242fc2d54f5d781cc510b648cceb08631f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "vcl/svapp.hxx"
21 #include "vcl/window.hxx"
22 #include "vcl/toolbox.hxx"
23 #include "vcl/menu.hxx"
25 #include "osx/a11yfocustracker.hxx"
27 #include "documentfocuslistener.hxx"
29 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
30 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
31 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
32 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
33 #include <com/sun/star/accessibility/AccessibleRole.hpp>
35 using namespace ::com::sun::star::accessibility;
36 using namespace ::com::sun::star::uno;
38 static inline vcl::Window *
39 getWindow(const ::VclSimpleEvent *pEvent)
41 return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow();
44 // callback function for Application::addEventListener
46 sal_IntPtr AquaA11yFocusTracker::WindowEventHandler(
47 void * pThis, void * pCaller)
49 AquaA11yFocusTracker *pFocusTracker = static_cast<AquaA11yFocusTracker *>(
50 pThis);
51 VclSimpleEvent const *pEvent = static_cast<VclSimpleEvent const *>(pCaller);
52 switch (pEvent->GetId())
54 case VCLEVENT_WINDOW_PAINT:
55 pFocusTracker-> toolbox_open_floater( getWindow(pEvent) );
56 break;
57 case VCLEVENT_WINDOW_GETFOCUS:
58 pFocusTracker->window_got_focus( getWindow(pEvent) );
59 break;
60 case VCLEVENT_OBJECT_DYING:
61 pFocusTracker->m_aDocumentWindowList.erase( getWindow(pEvent) );
62 // intentional pass through ..
63 case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
64 pFocusTracker->toolbox_highlight_off( getWindow(pEvent) );
65 break;
66 case VCLEVENT_TOOLBOX_HIGHLIGHT:
67 pFocusTracker->toolbox_highlight_on( getWindow(pEvent) );
68 break;
69 case VCLEVENT_TABPAGE_ACTIVATE:
70 pFocusTracker->tabpage_activated( getWindow(pEvent) );
71 break;
72 case VCLEVENT_MENU_HIGHLIGHT:
73 // Inspired by code in WindowEventHandler in
74 // vcl/unx/gtk/a11y/atkutil.cxx, find out what kind of event
75 // it is to avoid blindly using a static_cast and crash,
76 // fdo#47275.
77 if( const VclMenuEvent* pMenuEvent = dynamic_cast < const VclMenuEvent* > (pEvent) )
79 pFocusTracker->menu_highlighted( pMenuEvent );
81 else if( const VclAccessibleEvent* pAccEvent = dynamic_cast < const VclAccessibleEvent* > (pEvent) )
83 Reference< XAccessible > xAccessible = pAccEvent->GetAccessible();
84 if( xAccessible.is() )
85 pFocusTracker->setFocusedObject( xAccessible );
87 break;
88 default:
89 break;
92 return 0;
95 AquaA11yFocusTracker::AquaA11yFocusTracker() :
96 m_aWindowEventLink(this, WindowEventHandler),
97 m_xDocumentFocusListener(new DocumentFocusListener(*this))
99 Application::AddEventListener(m_aWindowEventLink);
100 window_got_focus(Application::GetFocusWindow());
103 void AquaA11yFocusTracker::setFocusedObject(const Reference< XAccessible >& xAccessible)
105 if( xAccessible != m_xFocusedObject )
107 m_xFocusedObject = xAccessible;
109 if( m_aFocusListener.is() )
110 m_aFocusListener->focusedObjectChanged(xAccessible);
114 void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox)
116 Reference< XAccessible > xAccessible( pToolBox->GetAccessible() );
118 if( xAccessible.is() )
120 Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
122 if( xContext.is() )
124 sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
125 if( nPos != TOOLBOX_ITEM_NOTFOUND )
126 setFocusedObject( xContext->getAccessibleChild( nPos ) );
131 void AquaA11yFocusTracker::toolbox_open_floater(vcl::Window *pWindow)
133 bool bToolboxFound = false;
134 bool bFloatingWindowFound = false;
135 vcl::Window * pFloatingWindow = NULL;
136 while ( pWindow != NULL ) {
137 if ( pWindow->GetType() == WINDOW_TOOLBOX ) {
138 bToolboxFound = true;
139 } else if ( pWindow->GetType() == WINDOW_FLOATINGWINDOW ) {
140 bFloatingWindowFound = true;
141 pFloatingWindow = pWindow;
143 pWindow = pWindow->GetParent();
145 if ( bToolboxFound && bFloatingWindowFound ) {
146 Reference < XAccessible > rxAccessible = pFloatingWindow -> GetAccessible();
147 if ( ! rxAccessible.is() ) {
148 return;
150 Reference < XAccessibleContext > rxContext = rxAccessible -> getAccessibleContext();
151 if ( ! rxContext.is() ) {
152 return;
154 if ( rxContext -> getAccessibleChildCount() > 0 ) {
155 Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
156 if ( ! rxAccessibleChild.is() ) {
157 return;
159 setFocusedObject ( rxAccessibleChild );
164 void AquaA11yFocusTracker::toolbox_highlight_on(vcl::Window *pWindow)
166 // Make sure either the toolbox or its parent toolbox has the focus
167 if ( ! pWindow->HasFocus() )
169 ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
170 if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
171 return;
174 notify_toolbox_item_focus(static_cast <ToolBox *> (pWindow));
177 void AquaA11yFocusTracker::toolbox_highlight_off(vcl::Window *pWindow)
179 ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
181 // Notify when leaving sub toolboxes
182 if( pToolBoxParent && pToolBoxParent->HasFocus() )
183 notify_toolbox_item_focus( pToolBoxParent );
186 void AquaA11yFocusTracker::tabpage_activated(vcl::Window *pWindow)
188 Reference< XAccessible > xAccessible( pWindow->GetAccessible() );
190 if( xAccessible.is() )
192 Reference< XAccessibleSelection > xSelection(xAccessible->getAccessibleContext(), UNO_QUERY);
194 if( xSelection.is() )
195 setFocusedObject( xSelection->getSelectedAccessibleChild(0) );
199 void AquaA11yFocusTracker::menu_highlighted(const VclMenuEvent *pEvent)
201 Menu * pMenu = pEvent->GetMenu();
203 if( pMenu )
205 Reference< XAccessible > xAccessible( pMenu->GetAccessible() );
207 if( xAccessible.is() )
208 setFocusedObject( xAccessible );
212 void AquaA11yFocusTracker::window_got_focus(vcl::Window *pWindow)
214 // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
215 if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
216 return;
218 // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
219 if( pWindow->GetType() == WINDOW_TOOLBOX )
220 return;
222 if( pWindow->GetType() == WINDOW_TABCONTROL )
224 tabpage_activated( pWindow );
225 return;
228 Reference< XAccessible > xAccessible(pWindow->GetAccessible());
230 if( ! xAccessible.is() )
231 return;
233 Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
235 if( ! xContext.is() )
236 return;
238 Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
240 if( ! xStateSet.is() )
241 return;
243 /* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
244 * need to add listeners to the children instead of re-using the tabpage stuff
246 if( xStateSet->contains(AccessibleStateType::FOCUSED) && (pWindow->GetType() != WINDOW_TREELISTBOX) )
248 setFocusedObject( xAccessible );
250 else
252 if( m_aDocumentWindowList.find(pWindow) == m_aDocumentWindowList.end() )
254 m_aDocumentWindowList.insert(pWindow);
255 m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
257 #ifdef ENABLE_TRACING
258 else
259 fprintf(stderr, "Window %p already in the list\n", pWindow );
260 #endif
264 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */