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 * 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 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 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 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 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 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 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 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 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 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 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