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));
             }
         }
     }

Reply via email to