1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
*>(
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
) );
57 case VCLEVENT_WINDOW_GETFOCUS
:
58 pFocusTracker
->window_got_focus( getWindow(pEvent
) );
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
) );
66 case VCLEVENT_TOOLBOX_HIGHLIGHT
:
67 pFocusTracker
->toolbox_highlight_on( getWindow(pEvent
) );
69 case VCLEVENT_TABPAGE_ACTIVATE
:
70 pFocusTracker
->tabpage_activated( getWindow(pEvent
) );
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,
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
);
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());
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() ) {
150 Reference
< XAccessibleContext
> rxContext
= rxAccessible
-> getAccessibleContext();
151 if ( ! rxContext
.is() ) {
154 if ( rxContext
-> getAccessibleChildCount() > 0 ) {
155 Reference
< XAccessible
> rxAccessibleChild
= rxContext
-> getAccessibleChild( 0 );
156 if ( ! rxAccessibleChild
.is() ) {
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() )
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();
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
)
218 // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
219 if( pWindow
->GetType() == WINDOW_TOOLBOX
)
222 if( pWindow
->GetType() == WINDOW_TABCONTROL
)
224 tabpage_activated( pWindow
);
228 Reference
< XAccessible
> xAccessible(pWindow
->GetAccessible());
230 if( ! xAccessible
.is() )
233 Reference
< XAccessibleContext
> xContext
= xAccessible
->getAccessibleContext();
235 if( ! xContext
.is() )
238 Reference
< XAccessibleStateSet
> xStateSet
= xContext
->getAccessibleStateSet();
240 if( ! xStateSet
.is() )
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
);
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
259 fprintf(stderr
, "Window %p already in the list\n", pWindow
);
264 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */