tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / vcl / osx / a11yfocustracker.cxx
blob2aaa8b0a8e25a48fd3f081fdb16de53f86495134
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/AccessibleStateType.hpp>
32 #include <com/sun/star/accessibility/AccessibleRole.hpp>
33 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
35 using namespace ::com::sun::star::accessibility;
36 using namespace ::com::sun::star::lang;
37 using namespace ::com::sun::star::uno;
39 AquaA11yFocusTracker& TheAquaA11yFocusTracker()
41 static AquaA11yFocusTracker SINGLETON;
42 return SINGLETON;
45 static vcl::Window *
46 getWindow(const ::VclSimpleEvent *pEvent)
48 return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow();
51 // callback function for Application::addEventListener
53 void AquaA11yFocusTracker::WindowEventHandler(void * pThis, VclSimpleEvent& rEvent)
55 AquaA11yFocusTracker *pFocusTracker = static_cast<AquaA11yFocusTracker *>(
56 pThis);
57 switch (rEvent.GetId())
59 case VclEventId::WindowPaint:
60 pFocusTracker-> toolbox_open_floater( getWindow(&rEvent) );
61 break;
62 case VclEventId::WindowGetFocus:
63 pFocusTracker->window_got_focus( getWindow(&rEvent) );
64 break;
65 case VclEventId::ObjectDying:
66 pFocusTracker->m_aDocumentWindowList.erase( getWindow(&rEvent) );
67 [[fallthrough]];
68 case VclEventId::ToolboxHighlightOff:
69 pFocusTracker->toolbox_highlight_off( getWindow(&rEvent) );
70 break;
71 case VclEventId::ToolboxHighlight:
72 pFocusTracker->toolbox_highlight_on( getWindow(&rEvent) );
73 break;
74 case VclEventId::TabpageActivate:
75 pFocusTracker->tabpage_activated( getWindow(&rEvent) );
76 break;
77 case VclEventId::MenuHighlight:
78 // Inspired by code in WindowEventHandler in
79 // vcl/unx/gtk/a11y/atkutil.cxx, find out what kind of event
80 // it is to avoid blindly using a static_cast and crash,
81 // fdo#47275.
82 if( const VclMenuEvent* pMenuEvent = dynamic_cast < const VclMenuEvent* > (&rEvent) )
84 pFocusTracker->menu_highlighted( pMenuEvent );
86 break;
87 default:
88 break;
92 AquaA11yFocusTracker::AquaA11yFocusTracker() :
93 m_aWindowEventLink(this, WindowEventHandler),
94 m_xDocumentFocusListener(new DocumentFocusListener(*this))
96 Application::AddEventListener(m_aWindowEventLink);
97 window_got_focus(Application::GetFocusWindow());
100 AquaA11yFocusTracker::~AquaA11yFocusTracker() {}
102 void AquaA11yFocusTracker::setFocusedObject(const Reference< XAccessible >& xAccessible)
104 if( xAccessible != m_xFocusedObject )
106 m_xFocusedObject = xAccessible;
108 if( m_aFocusListener.is() )
109 m_aFocusListener->focusedObjectChanged(xAccessible);
113 void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox)
115 Reference< XAccessible > xAccessible( pToolBox->GetAccessible() );
117 if( xAccessible.is() )
119 Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
121 if( xContext.is() )
123 try {
124 ToolBox::ImplToolItems::size_type nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
125 if( nPos != ToolBox::ITEM_NOTFOUND )
126 setFocusedObject( xContext->getAccessibleChild( nPos ) );
127 //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
129 catch (const IndexOutOfBoundsException&)
131 SAL_WARN("vcl", "Accessible object has invalid index in parent");
137 void AquaA11yFocusTracker::toolbox_open_floater(vcl::Window *pWindow)
139 bool bToolboxFound = false;
140 bool bFloatingWindowFound = false;
141 vcl::Window * pFloatingWindow = nullptr;
142 while ( pWindow != nullptr ) {
143 if ( pWindow->GetType() == WindowType::TOOLBOX ) {
144 bToolboxFound = true;
145 } else if ( pWindow->GetType() == WindowType::FLOATINGWINDOW ) {
146 bFloatingWindowFound = true;
147 pFloatingWindow = pWindow;
149 pWindow = pWindow->GetParent();
151 if ( bToolboxFound && bFloatingWindowFound ) {
152 Reference < XAccessible > rxAccessible = pFloatingWindow -> GetAccessible();
153 if ( ! rxAccessible.is() ) {
154 return;
156 Reference < XAccessibleContext > rxContext = rxAccessible -> getAccessibleContext();
157 if ( ! rxContext.is() ) {
158 return;
160 if ( rxContext -> getAccessibleChildCount() > 0 ) {
161 try {
162 Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
163 if ( ! rxAccessibleChild.is() ) {
164 return;
166 setFocusedObject ( rxAccessibleChild );
168 catch (const IndexOutOfBoundsException&)
170 SAL_WARN("vcl", "No valid accessible objects in parent");
176 void AquaA11yFocusTracker::toolbox_highlight_on(vcl::Window *pWindow)
178 // Make sure either the toolbox or its parent toolbox has the focus
179 if ( ! pWindow->HasFocus() )
181 ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
182 if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
183 return;
186 notify_toolbox_item_focus(static_cast <ToolBox *> (pWindow));
189 void AquaA11yFocusTracker::toolbox_highlight_off(vcl::Window const *pWindow)
191 ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
193 // Notify when leaving sub toolboxes
194 if( pToolBoxParent && pToolBoxParent->HasFocus() )
195 notify_toolbox_item_focus( pToolBoxParent );
198 void AquaA11yFocusTracker::tabpage_activated(vcl::Window *pWindow)
200 Reference< XAccessible > xAccessible( pWindow->GetAccessible() );
202 if( xAccessible.is() )
204 Reference< XAccessibleSelection > xSelection(xAccessible->getAccessibleContext(), UNO_QUERY);
206 if( xSelection.is() )
207 setFocusedObject( xSelection->getSelectedAccessibleChild(0) );
211 void AquaA11yFocusTracker::menu_highlighted(const VclMenuEvent *pEvent)
213 Menu * pMenu = pEvent->GetMenu();
215 if( pMenu )
217 Reference< XAccessible > xAccessible( pMenu->GetAccessible() );
219 if( xAccessible.is() )
220 setFocusedObject( xAccessible );
224 void AquaA11yFocusTracker::window_got_focus(vcl::Window *pWindow)
226 // The menu bar is handled through VclEventId::MenuHighlightED
227 if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WindowType::MENUBARWINDOW )
228 return;
230 // ToolBoxes are handled through VclEventId::ToolboxHighlight
231 if( pWindow->GetType() == WindowType::TOOLBOX )
232 return;
234 if( pWindow->GetType() == WindowType::TABCONTROL )
236 tabpage_activated( pWindow );
237 return;
240 Reference< XAccessible > xAccessible(pWindow->GetAccessible());
242 if( ! xAccessible.is() )
243 return;
245 Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
247 if( ! xContext.is() )
248 return;
250 sal_Int64 nStateSet = xContext->getAccessibleStateSet();
252 if( ! nStateSet )
253 return;
255 /* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
256 * need to add listeners to the children instead of re-using the tabpage stuff
258 if( (nStateSet & AccessibleStateType::FOCUSED) && (pWindow->GetType() != WindowType::TREELISTBOX) )
260 setFocusedObject( xAccessible );
262 else
264 if( m_aDocumentWindowList.insert(pWindow).second )
265 m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, nStateSet);
269 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */