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