1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include "vcl/svapp.hxx"
28 #include "vcl/window.hxx"
29 #include "vcl/toolbox.hxx"
30 #include "vcl/menu.hxx"
31 
32 #include "aqua/aqua11yfocustracker.hxx"
33 
34 #include "documentfocuslistener.hxx"
35 
36 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
37 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
38 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
39 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
40 #include <com/sun/star/accessibility/AccessibleRole.hpp>
41 
42 using namespace ::com::sun::star::accessibility;
43 using namespace ::com::sun::star::uno;
44 
45 //------------------------------------------------------------------------------
46 
47 static inline Window *
getWindow(const::VclSimpleEvent * pEvent)48 getWindow(const ::VclSimpleEvent *pEvent)
49 {
50 	return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow();
51 }
52 
53 
54 //------------------------------------------------------------------------------
55 
56 // callback function for Application::addEventListener
57 
WindowEventHandler(AquaA11yFocusTracker * pFocusTracker,::VclSimpleEvent const * pEvent)58 long AquaA11yFocusTracker::WindowEventHandler(AquaA11yFocusTracker *pFocusTracker, ::VclSimpleEvent const *pEvent)
59 {
60     switch (pEvent->GetId())
61     {
62     case VCLEVENT_WINDOW_PAINT:
63         pFocusTracker-> toolbox_open_floater( getWindow(pEvent) );
64         break;
65     case VCLEVENT_WINDOW_GETFOCUS:
66         pFocusTracker->window_got_focus( getWindow(pEvent) );
67         break;
68     case VCLEVENT_OBJECT_DYING:
69         pFocusTracker->m_aDocumentWindowList.erase( getWindow(pEvent) );
70         // intentional pass through ..
71     case VCLEVENT_TOOLBOX_HIGHLIGHTOFF:
72         pFocusTracker->toolbox_highlight_off( getWindow(pEvent) );
73         break;
74 	case VCLEVENT_TOOLBOX_HIGHLIGHT:
75         pFocusTracker->toolbox_highlight_on( getWindow(pEvent) );
76         break;
77     case VCLEVENT_TABPAGE_ACTIVATE:
78         pFocusTracker->tabpage_activated( getWindow(pEvent) );
79         break;
80     case VCLEVENT_MENU_HIGHLIGHT:
81         pFocusTracker->menu_highlighted( static_cast < const VclMenuEvent * > (pEvent) );
82         break;
83     default:
84 	    break;
85 	};
86 
87 	return 0;
88 }
89 
90 //------------------------------------------------------------------------------
91 
AquaA11yFocusTracker()92 AquaA11yFocusTracker::AquaA11yFocusTracker() :
93     m_aWindowEventLink(this, (PSTUB) WindowEventHandler),
94     m_xDocumentFocusListener(new DocumentFocusListener(*this))
95 {
96     Application::AddEventListener(m_aWindowEventLink);
97     window_got_focus(Application::GetFocusWindow());
98 }
99 
100 //------------------------------------------------------------------------------
101 
setFocusedObject(const Reference<XAccessible> & xAccessible)102 void AquaA11yFocusTracker::setFocusedObject(const Reference< XAccessible >& xAccessible)
103 {
104     if( xAccessible != m_xFocusedObject )
105     {
106         m_xFocusedObject = xAccessible;
107 
108         if( m_aFocusListener.is() )
109             m_aFocusListener->focusedObjectChanged(xAccessible);
110     }
111 }
112 
113 //------------------------------------------------------------------------------
114 
notify_toolbox_item_focus(ToolBox * pToolBox)115 void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox)
116 {
117     Reference< XAccessible > xAccessible( pToolBox->GetAccessible() );
118 
119     if( xAccessible.is() )
120     {
121         Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext());
122 
123         if( xContext.is() )
124         {
125             sal_Int32 nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
126             if( nPos != TOOLBOX_ITEM_NOTFOUND )
127                 setFocusedObject( xContext->getAccessibleChild( nPos ) );
128         }
129     }
130 }
131 
132 //------------------------------------------------------------------------------
133 
toolbox_open_floater(Window * pWindow)134 void AquaA11yFocusTracker::toolbox_open_floater(Window *pWindow)
135 {
136     bool bToolboxFound = false;
137     bool bFloatingWindowFound = false;
138     Window * pFloatingWindow = NULL;
139     while ( pWindow != NULL ) {
140         if ( pWindow->GetType() == WINDOW_TOOLBOX ) {
141             bToolboxFound = true;
142         } else if ( pWindow->GetType() == WINDOW_FLOATINGWINDOW ) {
143             bFloatingWindowFound = true;
144             pFloatingWindow = pWindow;
145         }
146         pWindow = pWindow->GetParent();
147     }
148     if ( bToolboxFound && bFloatingWindowFound ) {
149         Reference < XAccessible > rxAccessible = pFloatingWindow -> GetAccessible();
150         if ( ! rxAccessible.is() ) {
151             return;
152         }
153         Reference < XAccessibleContext > rxContext = rxAccessible -> getAccessibleContext();
154         if ( ! rxContext.is() ) {
155             return;
156         }
157         if ( rxContext -> getAccessibleChildCount() > 0 ) {
158             Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
159             if ( ! rxAccessibleChild.is() ) {
160                 return;
161             }
162             setFocusedObject ( rxAccessibleChild );
163         }
164     }
165 }
166 
167 //------------------------------------------------------------------------------
168 
toolbox_highlight_on(Window * pWindow)169 void AquaA11yFocusTracker::toolbox_highlight_on(Window *pWindow)
170 {
171     // Make sure either the toolbox or its parent toolbox has the focus
172     if ( ! pWindow->HasFocus() )
173     {
174         ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
175         if ( ! pToolBoxParent || ! pToolBoxParent->HasFocus() )
176             return;
177     }
178 
179     notify_toolbox_item_focus(static_cast <ToolBox *> (pWindow));
180 }
181 
182 //------------------------------------------------------------------------------
183 
toolbox_highlight_off(Window * pWindow)184 void AquaA11yFocusTracker::toolbox_highlight_off(Window *pWindow)
185 {
186     ToolBox* pToolBoxParent = dynamic_cast< ToolBox * >( pWindow->GetParent() );
187 
188     // Notify when leaving sub toolboxes
189     if( pToolBoxParent && pToolBoxParent->HasFocus() )
190         notify_toolbox_item_focus( pToolBoxParent );
191 }
192 
193 //------------------------------------------------------------------------------
194 
tabpage_activated(Window * pWindow)195 void AquaA11yFocusTracker::tabpage_activated(Window *pWindow)
196 {
197     Reference< XAccessible > xAccessible( pWindow->GetAccessible() );
198 
199     if( xAccessible.is() )
200     {
201         Reference< XAccessibleSelection > xSelection(xAccessible->getAccessibleContext(), UNO_QUERY);
202 
203         if( xSelection.is() )
204             setFocusedObject( xSelection->getSelectedAccessibleChild(0) );
205     }
206 }
207 
208 //------------------------------------------------------------------------------
209 
menu_highlighted(const VclMenuEvent * pEvent)210 void AquaA11yFocusTracker::menu_highlighted(const VclMenuEvent *pEvent)
211 {
212     Menu * pMenu = pEvent->GetMenu();
213 
214     if( pMenu )
215     {
216         Reference< XAccessible > xAccessible( pMenu->GetAccessible() );
217 
218         if( xAccessible.is() )
219             setFocusedObject( xAccessible );
220     }
221 }
222 
223 //------------------------------------------------------------------------------
224 
window_got_focus(Window * pWindow)225 void AquaA11yFocusTracker::window_got_focus(Window *pWindow)
226 {
227     // The menu bar is handled through VCLEVENT_MENU_HIGHLIGHTED
228     if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WINDOW_MENUBARWINDOW )
229         return;
230 
231     // ToolBoxes are handled through VCLEVENT_TOOLBOX_HIGHLIGHT
232     if( pWindow->GetType() == WINDOW_TOOLBOX )
233         return;
234 
235     if( pWindow->GetType() == WINDOW_TABCONTROL )
236     {
237         tabpage_activated( pWindow );
238         return;
239     }
240 
241     Reference< XAccessible > xAccessible(pWindow->GetAccessible());
242 
243     if( ! xAccessible.is() )
244         return;
245 
246     Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext();
247 
248     if( ! xContext.is() )
249         return;
250 
251     Reference< XAccessibleStateSet > xStateSet = xContext->getAccessibleStateSet();
252 
253     if( ! xStateSet.is() )
254         return;
255 
256 /* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we
257  * need to add listeners to the children instead of re-using the tabpage stuff
258  */
259     if( xStateSet->contains(AccessibleStateType::FOCUSED) && (pWindow->GetType() != WINDOW_TREELISTBOX) )
260     {
261         setFocusedObject( xAccessible );
262     }
263     else
264     {
265         if( m_aDocumentWindowList.find(pWindow) == m_aDocumentWindowList.end() )
266         {
267             m_aDocumentWindowList.insert(pWindow);
268             m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet);
269         }
270 #ifdef ENABLE_TRACING
271         else
272             fprintf(stderr, "Window %p already in the list\n", pWindow );
273 #endif
274     }
275 }
276