vcl/unx/gtk3/a11y/atkutil.cxx | 205 ++++++------------------------------------ 1 file changed, 30 insertions(+), 175 deletions(-)
New commits: commit c45c64aeb57dce91965d7be54601128946455c90 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Mon May 6 14:44:36 2024 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Tue May 7 06:05:55 2024 +0200 tdf#160806 tdf#160837 gtk3 a11y: Drop handling of some VclEventIds Drop custom handling for VCL events `VclEventId::WindowGetFocus` and `VclEventId::ObjectDying` in the gtk3 a11y bridge. In my understanding, the a11y bridge should not have to handle any of these by itself, but all relevant a11y events should be forwarded to the a11y listener as an appropriate `AccessibleEventObject` and be handled by the a11y event listener instead, see `AtkListener::notifyEvent` for the gtk3 implementation. In a quick test with Orca, I didn't notice anything not being announced anymore with this change in place. If something is still not announced due to this change, a proper fix is likely to make sure that a proper a11y event is emitted and handled in `AtkListener::notifyEvent` instead. Note how `VCLXAccessibleComponent::ProcessWindowEvent` already handles the `VclEventId::WindowGetFocus` and `VclEventId::ObjectDying` window events. This (or a corresponding override in a subclass) and `VclEventId::ObjectDying` are potentially good places to start analysis if this change here results in any regressions. Dropping this custom handling also fixes one problematic way that an accessible object would be created for the work window/root panel (e.g. in Writer) from the corresponding XAccessible independent of the corresponding GTK Widget hierarchy, thus breaking the a11y hierarchy (ascending the tree doesn't work, see tdf#160806). This could be observed by starting LO Writer with the gtk3 VCL plugin first, then start Accerciser. Printing the a11y info for the parent of the object with role root pane as shown in Accerciser: In [1]: acc.parent Out[1]: <Atspi.Accessible object at 0x7f1f0f5b7780 (AtspiAccessible at 0x41f9c60)> In [2]: acc.parent.role Out[2]: <enum ATSPI_ROLE_FRAME of type Atspi.Role> In [3]: acc.parent.role Out[3]: <enum ATSPI_ROLE_FRAME of type Atspi.Role> Selecting the object shown as the parent in Accerciser's tree of LO's a11y hierarchy shows that this is not the same object: In [4]: acc Out[4]: <Atspi.Accessible object at 0x7f1f05f92100 (AtspiAccessible at 0x2d45c80)> In [5]: acc.role Out[5]: <enum ATSPI_ROLE_PANEL of type Atspi.Role> and consequently, the first child of that accessible doesn't report the accessible itself as its parent: In [6]: acc.get_child_at_index(0).parent == acc Out[6]: False The commit message of commit 252b1591d5e4e3adbf7063b56c2b578fe046ad3d Author: Michael Weghorn <m.wegh...@posteo.de> Date: Tue Apr 30 15:30:52 2024 +0200 tdf#159369 tdf#160806 tdf#160837 gtk3 a11y: Don't skip parents one way has some more background information. Extra local change in place showing where the accessible object gets created (used for analysis with rr): diff --git a/vcl/unx/gtk3/a11y/atkwrapper.cxx b/vcl/unx/gtk3/a11y/atkwrapper.cxx index db0aa1dbc907..c73d28987f26 100644 --- a/vcl/unx/gtk3/a11y/atkwrapper.cxx +++ b/vcl/unx/gtk3/a11y/atkwrapper.cxx @@ -977,6 +977,10 @@ atk_object_wrapper_new( const css::uno::Reference< css::accessibility::XAccessib AtkObject* atk_obj = ATK_OBJECT(pWrap); atk_obj->role = mapToAtkRole(xContext->getAccessibleRole(), xContext->getAccessibleStateSet()); + // NOTE: the object of interest is root pane, breaks the a11y hierarchy + // as it reports wrong parent + if (atk_obj->role == ATK_ROLE_ROOT_PANE) + SAL_WARN("vcl.gtk", "Creating wrapper for root pane"); atk_obj->accessible_parent = parent; ooo_wrapper_registry_add( rxAccessible, atk_obj ); Sample backtrace of how the problematic accessible object got created without this commit in place: 1 atk_object_wrapper_new atkwrapper.cxx 983 0x7fb5dda5ae8b 2 atk_object_wrapper_ref atkwrapper.cxx 948 0x7fb5dda5a800 3 atk_wrapper_notify_focus_change atkutil.cxx 47 0x7fb5dda4cab0 4 handle_get_focus atkutil.cxx 451 0x7fb5dda4debd 5 WindowEventHandler atkutil.cxx 512 0x7fb5dda4d9e3 6 Link<VclSimpleEvent&, void>::Call link.hxx 111 0x7fb5e81d4ef8 7 VclEventListeners::Call vclevent.cxx 46 0x7fb5e81d3f1a 8 Application::ImplCallEventListeners svapp.cxx 725 0x7fb5e8196b0d 9 vcl::Window::CallEventListeners event.cxx 225 0x7fb5e779f6ee 10 vcl::Window::PreNotify event.cxx 70 0x7fb5e779f58c 11 SystemWindow::PreNotify syswin.cxx 245 0x7fb5e788e470 12 vcl::Window::CompatPreNotify window.cxx 3941 0x7fb5e790cddd 13 ImplCallPreNotify winproc.cxx 69 0x7fb5e791d061 14 vcl::Window::ImplGrabFocus mouse.cxx 383 0x7fb5e782ffc5 15 vcl::Window::GrabFocus window.cxx 2988 0x7fb5e78fa027 16 vcl::Window::ImplAsyncFocusHdl winproc.cxx 2061 0x7fb5e7923386 17 vcl::Window::LinkStubImplAsyncFocusHdl winproc.cxx 2035 0x7fb5e792318d 18 Link<void *, void>::Call link.hxx 111 0x7fb5e792c298 19 ImplHandleUserEvent winproc.cxx 2287 0x7fb5e7927f79 20 ImplWindowFrameProc winproc.cxx 2851 0x7fb5e7924930 21 SalFrame::CallCallback salframe.hxx 312 0x7fb5e85a0310 22 SalGenericDisplay::ProcessEvent gendisp.cxx 66 0x7fb5e85cae6f 23 SalUserEventList::DispatchUserEvents(bool)::$_0::operator()() const salusereventlist.cxx 119 0x7fb5e80b49bd 24 SalUserEventList::DispatchUserEvents salusereventlist.cxx 120 0x7fb5e80b4864 25 SalGenericDisplay::DispatchInternalEvent gendisp.cxx 51 0x7fb5e85cadc5 26 call_userEventFn gtkdata.cxx 824 0x7fb5dda8e216 27 ?? 0x7fb5e47110d9 28 ?? 0x7fb5e4714317 29 g_main_context_iteration 0x7fb5e4714930 30 GtkSalData::Yield gtkdata.cxx 405 0x7fb5dda8ccef 31 GtkInstance::DoYield gtkinst.cxx 435 0x7fb5dda92173 32 ImplYield svapp.cxx 378 0x7fb5e8194dfc 33 Application::Yield svapp.cxx 466 0x7fb5e819470b 34 Application::Execute svapp.cxx 353 0x7fb5e81944a2 35 desktop::Desktop::Main app.cxx 1615 0x7fb5f13254fc 36 ImplSVMain svmain.cxx 229 0x7fb5e81b760e 37 SVMain svmain.cxx 261 0x7fb5e81b9659 38 soffice_main sofficemain.cxx 93 0x7fb5f13a7eb3 39 sal_main main.c 51 0x55b83ad6da5d 40 main main.c 49 0x55b83ad6da37 Sample backtrace for how the root pane a11y object is created for the good case, i.e. the case where the root pane's parent is set properly as it uses the GTK widget hierarchy (backtrace obtained from an rr run when first starting Accerciser, then LO, with master as of 7a895ec4205659038aa95941b65715fed1a3e7be + the same local change as mentioned above): 1 atk_object_wrapper_new atkwrapper.cxx 983 0x7f3799a5b48b 2 wrapper_factory_create_accessible atkfactory.cxx 83 0x7f3799a2c9c1 3 ooo_fixed_get_accessible atkfactory.cxx 95 0x7f3799a2c6d2 4 ?? 0x7f37993ec4c8 5 ?? 0x7f3798c536d3 6 ?? 0x7f379f9110d9 7 ?? 0x7f379f914317 8 g_main_context_iteration 0x7f379f914930 9 GtkSalData::Yield gtkdata.cxx 405 0x7f3799a8d2df 10 GtkInstance::DoYield gtkinst.cxx 435 0x7f3799a92743 11 ImplYield svapp.cxx 378 0x7f37a4194dfc 12 Application::Yield svapp.cxx 466 0x7f37a419470b 13 Application::Execute svapp.cxx 353 0x7f37a41944a2 14 desktop::Desktop::Main app.cxx 1615 0x7f37ad3254fc 15 ImplSVMain svmain.cxx 229 0x7f37a41b760e 16 SVMain svmain.cxx 261 0x7f37a41b9659 17 soffice_main sofficemain.cxx 93 0x7f37ad3a7eb3 18 sal_main main.c 51 0x560d4a1f4a5d 19 main main.c 49 0x560d4a1f4a37 Similar changes for other events will follow. (Keeping them separate for easier bibisecting/analysis if any of those changes causes regressions.) Change-Id: I00e62016ced2fbb8796960671f5e58a3ceac4b29 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167208 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/unx/gtk3/a11y/atkutil.cxx b/vcl/unx/gtk3/a11y/atkutil.cxx index 9936bc350b0f..239ce1c49dd9 100644 --- a/vcl/unx/gtk3/a11y/atkutil.cxx +++ b/vcl/unx/gtk3/a11y/atkutil.cxx @@ -378,22 +378,6 @@ static void handle_toolbox_buttonchange(VclWindowEvent const *pEvent) } } -/*****************************************************************************/ - -namespace { - -struct WindowList { - ~WindowList() { assert(list.empty()); }; - // needs to be empty already on DeInitVCL, but at least check it's empty - // on exit - - std::set< VclPtr<vcl::Window> > list; -}; - -WindowList g_aWindowList; - -} - rtl::Reference<DocumentFocusListener> GtkSalData::GetDocumentFocusListener() { rtl::Reference<DocumentFocusListener> xDFL = m_xDocumentFocusListener.get(); @@ -405,69 +389,6 @@ rtl::Reference<DocumentFocusListener> GtkSalData::GetDocumentFocusListener() return xDFL; } -static void handle_get_focus(::VclWindowEvent const * pEvent) -{ - GtkSalData *const pSalData(GetGtkSalData()); - assert(pSalData); - - rtl::Reference<DocumentFocusListener> xDocumentFocusListener(pSalData->GetDocumentFocusListener()); - - vcl::Window *pWindow = pEvent->GetWindow(); - - // The menu bar is handled through VclEventId::MenuHighlightED - if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WindowType::MENUBARWINDOW ) - return; - - // ToolBoxes are handled through VclEventId::ToolboxHighlight - if( pWindow->GetType() == WindowType::TOOLBOX ) - return; - - if( pWindow->GetType() == WindowType::TABCONTROL ) - { - handle_tabpage_activated( pWindow ); - return; - } - - uno::Reference< accessibility::XAccessible > xAccessible = - pWindow->GetAccessible(); - - if( ! xAccessible.is() ) - return; - - uno::Reference< accessibility::XAccessibleContext > xContext = - xAccessible->getAccessibleContext(); - - if( ! xContext.is() ) - return; - - sal_Int64 nStateSet = xContext->getAccessibleStateSet(); - -/* the UNO ToolBox wrapper does not (yet?) support XAccessibleSelection, so we - * need to add listeners to the children instead of re-using the tabpage stuff - */ - if( (nStateSet & accessibility::AccessibleStateType::FOCUSED) && - ( pWindow->GetType() != WindowType::TREELISTBOX ) ) - { - atk_wrapper_notify_focus_change(xAccessible); - } - else - { - if( g_aWindowList.list.insert(pWindow).second ) - { - try - { - xDocumentFocusListener->attachRecursive(xAccessible, xContext, nStateSet); - } - catch (const uno::Exception&) - { - g_warning( "Exception caught processing focus events" ); - } - } - } -} - -/*****************************************************************************/ - static void handle_menu_highlighted(::VclMenuEvent const * pEvent) { try @@ -502,27 +423,6 @@ static void WindowEventHandler(void *, VclSimpleEvent& rEvent) { switch (rEvent.GetId()) { - case VclEventId::WindowShow: - break; - case VclEventId::WindowHide: - break; - case VclEventId::WindowClose: - break; - case VclEventId::WindowGetFocus: - handle_get_focus(static_cast< ::VclWindowEvent const * >(&rEvent)); - break; - case VclEventId::WindowLoseFocus: - break; - case VclEventId::WindowMinimize: - break; - case VclEventId::WindowNormalize: - break; - case VclEventId::WindowKeyInput: - case VclEventId::WindowKeyUp: - case VclEventId::WindowCommand: - case VclEventId::WindowMouseMove: - break; - case VclEventId::MenuHighlight: if (const VclMenuEvent* pMenuEvent = dynamic_cast<const VclMenuEvent*>(&rEvent)) { @@ -538,9 +438,6 @@ static void WindowEventHandler(void *, VclSimpleEvent& rEvent) handle_toolbox_buttonchange(static_cast< ::VclWindowEvent const * >(&rEvent)); break; - case VclEventId::ObjectDying: - g_aWindowList.list.erase( static_cast< ::VclWindowEvent const * >(&rEvent)->GetWindow() ); - [[fallthrough]]; case VclEventId::ToolboxHighlightOff: handle_toolbox_highlightoff(static_cast< ::VclWindowEvent const * >(&rEvent)->GetWindow()); break; commit 1b9041a7c97c31a12afe7b69f0e1e4005a819509 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Mon May 6 11:57:21 2024 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Tue May 7 06:05:50 2024 +0200 tdf#160806 tdf#160837 gtk3 a11y: Port from deprecated atk_focus_tracker_notify `atk_focus_tracker_notify` takes care of sending an "AtkObject:focus-event" event for the given object. However, both, `atk_focus_tracker_notify` and the "AtkObject:focus-event" ATK event (which triggers a "focus" AT-SPI event) are deprecated, quoting [1]: > Focus tracking has been dropped as a feature to be implemented by ATK > itself. As AtkObject::focus-event was deprecated in favor of a > AtkObject::state-change signal, in order to notify a focus change on > your implementation, you can use atk_object_notify_state_change() > instead. Move the existing call to `atk_object_notify_state_change` up and use instead of the deprecated function. For the example of the "Print" button in Writer's standard toolbar, it can now be seen that a "object:state-changed:focused" instead of a "focus" event is received with a corresponding listener when tabbing to the button and then further: Before: 88.7 focus:(0, 0, 0) source: [push button | Print] application: [application | soffice] 88.7 object:state-changed:focused(1, 0, 0) source: [push button | Print] application: [application | soffice] 89.4 object:state-changed:focused(0, 0, 0) source: [push button | Print] application: [application | soffice] After: 80.0 object:state-changed:focused(1, 0, 0) source: [push button | Print] application: [application | soffice] 80.0 object:state-changed:focused(1, 0, 0) source: [push button | Print] application: [application | soffice] 80.8 object:state-changed:focused(0, 0, 0) source: [push button | Print] application: [application | soffice] The first event is the one emitted fromt this place, the others are from elsewhere. This also already shows that duplicate events are sent. Eliminating those which also cause other problems is planned in upcoming steps. [1] https://docs.gtk.org/atk/func.focus_tracker_notify.html Change-Id: Ieb9d25445b620681b01b887c0c120c80a43379ef Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167207 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/vcl/unx/gtk3/a11y/atkutil.cxx b/vcl/unx/gtk3/a11y/atkutil.cxx index 88ebe460a7d4..9936bc350b0f 100644 --- a/vcl/unx/gtk3/a11y/atkutil.cxx +++ b/vcl/unx/gtk3/a11y/atkutil.cxx @@ -42,19 +42,16 @@ using namespace ::com::sun::star; static void -atk_wrapper_focus_tracker_notify(const uno::Reference<accessibility::XAccessible>& xAccessible) +atk_wrapper_notify_focus_change(const uno::Reference<accessibility::XAccessible>& xAccessible) { AtkObject *atk_obj = xAccessible.is() ? atk_object_wrapper_ref( xAccessible ) : nullptr; // Gail does not notify focus changes to NULL, so do we .. if( atk_obj ) { - SAL_WNODEPRECATED_DECLARATIONS_PUSH - atk_focus_tracker_notify(atk_obj); - SAL_WNODEPRECATED_DECLARATIONS_POP + atk_object_notify_state_change(atk_obj, ATK_STATE_FOCUSED, true); // #i93269# // emit text_caret_moved event for <XAccessibleText> object, // if cursor is inside the <XAccessibleText> object. - // also emit state-changed:focused event under the same condition. { AtkObjectWrapper* wrapper_obj = ATK_OBJECT_WRAPPER (atk_obj); if( wrapper_obj && !wrapper_obj->mpText.is() ) @@ -73,7 +70,6 @@ atk_wrapper_focus_tracker_notify(const uno::Reference<accessibility::XAccessible if ( caretPos != -1 ) { - atk_object_notify_state_change( atk_obj, ATK_STATE_FOCUSED, true ); g_signal_emit_by_name( atk_obj, "text_caret_moved", caretPos ); } } @@ -106,7 +102,7 @@ void DocumentFocusListener::notifyEvent( const accessibility::AccessibleEventObj aEvent.NewValue >>= nState; if( accessibility::AccessibleStateType::FOCUSED == nState ) - atk_wrapper_focus_tracker_notify(getAccessible(aEvent)); + atk_wrapper_notify_focus_change(getAccessible(aEvent)); break; } @@ -200,7 +196,7 @@ void DocumentFocusListener::attachRecursive( ) { if( nStateSet & accessibility::AccessibleStateType::FOCUSED ) - atk_wrapper_focus_tracker_notify(xAccessible); + atk_wrapper_notify_focus_change(xAccessible); uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY); @@ -296,7 +292,7 @@ static void handle_tabpage_activated(vcl::Window *pWindow) xAccessible->getAccessibleContext(), uno::UNO_QUERY); if( xSelection.is() ) - atk_wrapper_focus_tracker_notify(xSelection->getSelectedAccessibleChild(0)); + atk_wrapper_notify_focus_change(xSelection->getSelectedAccessibleChild(0)); } /*****************************************************************************/ @@ -321,7 +317,7 @@ static void notify_toolbox_item_focus(ToolBox *pToolBox) ToolBox::ImplToolItems::size_type nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() ); if( nPos != ToolBox::ITEM_NOTFOUND ) - atk_wrapper_focus_tracker_notify(xContext->getAccessibleChild(nPos)); + atk_wrapper_notify_focus_change(xContext->getAccessibleChild(nPos)); } static void handle_toolbox_highlight(vcl::Window *pWindow) @@ -452,7 +448,7 @@ static void handle_get_focus(::VclWindowEvent const * pEvent) if( (nStateSet & accessibility::AccessibleStateType::FOCUSED) && ( pWindow->GetType() != WindowType::TREELISTBOX ) ) { - atk_wrapper_focus_tracker_notify(xAccessible); + atk_wrapper_notify_focus_change(xAccessible); } else { @@ -488,7 +484,7 @@ static void handle_menu_highlighted(::VclMenuEvent const * pEvent) uno::Reference< accessibility::XAccessibleContext > xContext ( xAccessible->getAccessibleContext() ); if( xContext.is() ) - atk_wrapper_focus_tracker_notify(xContext->getAccessibleChild(nPos)); + atk_wrapper_notify_focus_change(xContext->getAccessibleChild(nPos)); } } } commit c1a7de292c3f1d1ec52dbda4c027dc91a9718777 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Mon May 6 11:31:10 2024 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Tue May 7 06:05:44 2024 +0200 tdf#160806 tdf#160837 gtk3 a11y: Don't use idle Don't use and idle to call the (deprecated) ATK focus tracker, but do so right away. Since this is no longer called in an idle, the SolarMutexGuard should also no longer be needed, so drop it. It's not clear why the focus event was handled in an idle ever since commit 3b5c378706e465f59d78f95fddc5eff9e1a8fe19 Author: RĂ¼diger Timm <r...@openoffice.org> Date: Fri May 5 09:58:25 2006 +0000 INTEGRATION: CWS atkbridge (1.1.2); FILE ADDED 2006/04/27 14:47:54 obr 1.1.2.17: #134576# move focus clearing code to atkwindow.cxx 2006/04/27 08:18:11 obr 1.1.2.16: #134571# toolbox items are no VCL windows 2006/03/31 12:19:40 obr 1.1.2.15: #i63583# eliminated warnings 2006/03/03 11:07:09 obr 1.1.2.14: #i47890# fixed a crash when event source does not implement XAccessibleContext 2006/03/01 11:04:11 obr 1.1.2.13: #i47890# recursivly attach listeners to windows of type TREELISTBOX 2006/02/16 11:07:11 obr 1.1.2.12: #i47890# ORoadmapIDHyperLabel is derived from FixedText 2006/02/15 12:42:56 obr 1.1.2.11: #i47890# simulate focus events for page tabs 2006/02/07 09:26:21 obr 1.1.2.10: #i47890# reduce amount of focus notifications 2006/01/12 13:56:14 obr 1.1.2.9: #i47890# Solaris compile fixes 2006/01/05 14:06:32 obr 1.1.2.8: #i47890# override toolkit name and version and reworked bridge initialization 2005/11/16 15:57:57 obr 1.1.2.7: fixed for menu state ARMED only valid during notification 2005/10/24 07:36:05 obr 1.1.2.6: #i47890# reset focused object on WINDOW_DEACTIVATE 2005/10/20 11:57:32 obr 1.1.2.5: #i47890# initially set name and description + disabled some tracing 2005/10/20 07:09:12 obr 1.1.2.4: #i47890# made cxx files standalone, avoid queryInterface on each API call and demacrofied try/catch to include appropriate warnings 2005/09/28 07:24:13 obr 1.1.2.3: #i47890# changed ref-counting/life cycle once again, adjust tree and role of dialogs and filter sub-menu windows 2005/09/26 11:01:01 obr 1.1.2.2: #i47890# reworked lifecycle of atk wrapper objects 2005/06/14 13:57:24 obr 1.1.2.1: #i47890# global focus event listening stuff With this in place, watching for "object:focus" events in Accerciser still shows such an event when e.g. tabbing through the standard toolbar in Writer. Example for when the "Save" button receives focus: 37.9 focus:(0, 0, 0) source: [push button | Save] application: [application | soffice] This is one step to port from the use of that deprecated focus tracker and clean up a11y event handling in the gtk3 VCL plugin. (Take one step at a time to keep the scope of the changes clearer and simplify identifying causes of any potential regressions.) (`git show --ignore-space-change` helps to see the "actual change" more clearly). Change-Id: Ia71b70bdf5d9db8fbb389f3c7366af48ee723af7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167206 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Jenkins diff --git a/vcl/unx/gtk3/a11y/atkutil.cxx b/vcl/unx/gtk3/a11y/atkutil.cxx index fc15351374fd..88ebe460a7d4 100644 --- a/vcl/unx/gtk3/a11y/atkutil.cxx +++ b/vcl/unx/gtk3/a11y/atkutil.cxx @@ -41,86 +41,48 @@ using namespace ::com::sun::star; -namespace -{ - uno::WeakReference< accessibility::XAccessible > theNextFocusObject; -} - -static guint focus_notify_handler = 0; - -/*****************************************************************************/ - -extern "C" { - -static gboolean -atk_wrapper_focus_idle_handler (gpointer data) +static void +atk_wrapper_focus_tracker_notify(const uno::Reference<accessibility::XAccessible>& xAccessible) { - SolarMutexGuard aGuard; - - focus_notify_handler = 0; - - uno::Reference< accessibility::XAccessible > xAccessible = theNextFocusObject; - if( xAccessible.get() == static_cast < accessibility::XAccessible * > (data) ) + AtkObject *atk_obj = xAccessible.is() ? atk_object_wrapper_ref( xAccessible ) : nullptr; + // Gail does not notify focus changes to NULL, so do we .. + if( atk_obj ) { - AtkObject *atk_obj = xAccessible.is() ? atk_object_wrapper_ref( xAccessible ) : nullptr; - // Gail does not notify focus changes to NULL, so do we .. - if( atk_obj ) + SAL_WNODEPRECATED_DECLARATIONS_PUSH + atk_focus_tracker_notify(atk_obj); + SAL_WNODEPRECATED_DECLARATIONS_POP + // #i93269# + // emit text_caret_moved event for <XAccessibleText> object, + // if cursor is inside the <XAccessibleText> object. + // also emit state-changed:focused event under the same condition. { - SAL_WNODEPRECATED_DECLARATIONS_PUSH - atk_focus_tracker_notify(atk_obj); - SAL_WNODEPRECATED_DECLARATIONS_POP - // #i93269# - // emit text_caret_moved event for <XAccessibleText> object, - // if cursor is inside the <XAccessibleText> object. - // also emit state-changed:focused event under the same condition. + AtkObjectWrapper* wrapper_obj = ATK_OBJECT_WRAPPER (atk_obj); + if( wrapper_obj && !wrapper_obj->mpText.is() ) { - AtkObjectWrapper* wrapper_obj = ATK_OBJECT_WRAPPER (atk_obj); - if( wrapper_obj && !wrapper_obj->mpText.is() ) + wrapper_obj->mpText.set(wrapper_obj->mpContext, css::uno::UNO_QUERY); + if ( wrapper_obj->mpText.is() ) { - wrapper_obj->mpText.set(wrapper_obj->mpContext, css::uno::UNO_QUERY); - if ( wrapper_obj->mpText.is() ) + gint caretPos = -1; + + try { + caretPos = wrapper_obj->mpText->getCaretPosition(); + } + catch(const uno::Exception&) { + g_warning( "Exception in getCaretPosition()" ); + } + + if ( caretPos != -1 ) { - gint caretPos = -1; - - try { - caretPos = wrapper_obj->mpText->getCaretPosition(); - } - catch(const uno::Exception&) { - g_warning( "Exception in getCaretPosition()" ); - } - - if ( caretPos != -1 ) - { - atk_object_notify_state_change( atk_obj, ATK_STATE_FOCUSED, true ); - g_signal_emit_by_name( atk_obj, "text_caret_moved", caretPos ); - } + atk_object_notify_state_change( atk_obj, ATK_STATE_FOCUSED, true ); + g_signal_emit_by_name( atk_obj, "text_caret_moved", caretPos ); } } } - g_object_unref(atk_obj); } + g_object_unref(atk_obj); } - - return false; } -} // extern "C" - -/*****************************************************************************/ - -static void -atk_wrapper_focus_tracker_notify_when_idle( const uno::Reference< accessibility::XAccessible > &xAccessible ) -{ - if( focus_notify_handler ) - g_source_remove(focus_notify_handler); - - theNextFocusObject = xAccessible; - - focus_notify_handler = g_idle_add (atk_wrapper_focus_idle_handler, xAccessible.get()); -} - -/*****************************************************************************/ - void DocumentFocusListener::disposing( const lang::EventObject& aEvent ) { @@ -144,7 +106,7 @@ void DocumentFocusListener::notifyEvent( const accessibility::AccessibleEventObj aEvent.NewValue >>= nState; if( accessibility::AccessibleStateType::FOCUSED == nState ) - atk_wrapper_focus_tracker_notify_when_idle( getAccessible(aEvent) ); + atk_wrapper_focus_tracker_notify(getAccessible(aEvent)); break; } @@ -238,7 +200,7 @@ void DocumentFocusListener::attachRecursive( ) { if( nStateSet & accessibility::AccessibleStateType::FOCUSED ) - atk_wrapper_focus_tracker_notify_when_idle( xAccessible ); + atk_wrapper_focus_tracker_notify(xAccessible); uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY); @@ -334,7 +296,7 @@ static void handle_tabpage_activated(vcl::Window *pWindow) xAccessible->getAccessibleContext(), uno::UNO_QUERY); if( xSelection.is() ) - atk_wrapper_focus_tracker_notify_when_idle( xSelection->getSelectedAccessibleChild(0) ); + atk_wrapper_focus_tracker_notify(xSelection->getSelectedAccessibleChild(0)); } /*****************************************************************************/ @@ -359,7 +321,7 @@ static void notify_toolbox_item_focus(ToolBox *pToolBox) ToolBox::ImplToolItems::size_type nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() ); if( nPos != ToolBox::ITEM_NOTFOUND ) - atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) ); + atk_wrapper_focus_tracker_notify(xContext->getAccessibleChild(nPos)); } static void handle_toolbox_highlight(vcl::Window *pWindow) @@ -490,7 +452,7 @@ static void handle_get_focus(::VclWindowEvent const * pEvent) if( (nStateSet & accessibility::AccessibleStateType::FOCUSED) && ( pWindow->GetType() != WindowType::TREELISTBOX ) ) { - atk_wrapper_focus_tracker_notify_when_idle( xAccessible ); + atk_wrapper_focus_tracker_notify(xAccessible); } else { @@ -526,7 +488,7 @@ static void handle_menu_highlighted(::VclMenuEvent const * pEvent) uno::Reference< accessibility::XAccessibleContext > xContext ( xAccessible->getAccessibleContext() ); if( xContext.is() ) - atk_wrapper_focus_tracker_notify_when_idle( xContext->getAccessibleChild( nPos ) ); + atk_wrapper_focus_tracker_notify(xContext->getAccessibleChild(nPos)); } } }