So far, the ValueItemAcc objects created by ValueSet were never disposed. While this is a preexisting issue, this started triggering crashes with the qt6 VCL plugin after Change-Id: If448008b3a6dc7b22a06b6ed551b08a40b2d5de3 Author: Michael Weghorn <m.weghorn@posteo.de> Date: Tue Feb 25 12:14:24 2025 +0100 valueset a11y: Use OAccessibleComponentHelper for ValueItemAcc as described in its commit message. Fix this by disposing the objects in ValueSet::ImplDeleteItems, and not just sending an AccessibleEventId::CHILD event. Adjust the logic to be independent of whether the item is visible, but instead do this for all items that have an associated ValueItemAcc. Add a new `bCreate` param to ValueSetItem::GetAccessible and pass false here to avoid creating new ones. In the ValueSet dtor, call `ImplDeleteItems` before invalidating the accessible object, as it may still be needed in `ImplDeleteItems` to send the events. This fixes the crash on exit for the scenario described in the above-mentioned commit. Backtrace of such a crash/assert: soffice.bin: /home/michi/development/git/libreoffice/comphelper/source/misc/accessibleeventnotifier.cxx:142: bool (anonymous namespace)::implLookupClient(const AccessibleEventNotifier::TClientId, ClientMap::iterator &): Assertion `rClients.end() != rPos && "AccessibleEventNotifier::implLookupClient: invalid client id " "(did you register your client?)!"' failed. [New Thread 9546.9547] [New Thread 9546.9548] [New Thread 9546.9549] [New Thread 9546.9557] Thread 1 received signal SIGABRT, Aborted. __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44 warning: 44 ./nptl/pthread_kill.c: No such file or directory (rr) bt #0 __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at ./nptl/pthread_kill.c:44 #1 0x00007ff8c289de2f in __pthread_kill_internal (threadid=<optimized out>, signo=6) at ./nptl/pthread_kill.c:78 #2 0x00007ff8c2849d02 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26 #3 0x00007ff8c28324f0 in __GI_abort () at ./stdlib/abort.c:79 #4 0x00007ff8c2832418 in __assert_fail_base (fmt=0x7ff8c29b6ca0 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x7ff8c0f27cc6 "rClients.end() != rPos && \"AccessibleEventNotifier::implLookupClient: invalid client id \" \"(did you register your client?)!\"", file=file@entry=0x7ff8c0f360b9 "/home/michi/development/git/libreoffice/comphelper/source/misc/accessibleeventnotifier.cxx", line=line@entry=142, function=function@entry=0x7ff8c0efd262 "bool (anonymous namespace)::implLookupClient(const AccessibleEventNotifier::TClientId, ClientMap::iterator &)") at ./assert/assert.c:96 #5 0x00007ff8c2842612 in __assert_fail (assertion=0x7ff8c0f27cc6 "rClients.end() != rPos && \"AccessibleEventNotifier::implLookupClient: invalid client id \" \"(did you register your client?)!\"", file=0x7ff8c0f360b9 "/home/michi/development/git/libreoffice/comphelper/source/misc/accessibleeventnotifier.cxx", line=142, function=0x7ff8c0efd262 "bool (anonymous namespace)::implLookupClient(const AccessibleEventNotifier::TClientId, ClientMap::iterator &)") at ./assert/assert.c:105 #6 0x00007ff8c10eb4c8 in (anonymous namespace)::implLookupClient (nClient=24, rPos=...) at /home/michi/development/git/libreoffice/comphelper/source/misc/accessibleeventnotifier.cxx:140 #7 0x00007ff8c10eb938 in comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing (_nClient=24, _rxEventSource=uno::Reference to (ValueItemAcc *) 0x558da6f7a220) at /home/michi/development/git/libreoffice/comphelper/source/misc/accessibleeventnotifier.cxx:185 #8 0x00007ff8c10e751d in comphelper::OCommonAccessibleComponent::disposing (this=0x558da6f7a220) at /home/michi/development/git/libreoffice/comphelper/source/misc/accessiblecomponenthelper.cxx:61 #9 0x00007ff8c0b3cee0 in cppu::WeakComponentImplHelperBase::dispose (this=0x558da6f7a220) at /home/michi/development/git/libreoffice/cppuhelper/source/implbase.cxx:104 #10 0x00007ff8bb84a0c5 in cppu::PartialWeakComponentImplHelper<com::sun:⭐:accessibility::XAccessibleContext2, com::sun:⭐:accessibility::XAccessibleEventBroadcaster>::dispose (this=0x558da6f7a220) at include/cppuhelper/compbase.hxx:90 #11 0x00007ff8c0b3cc07 in cppu::WeakComponentImplHelperBase::release (this=0x558da6f7a220) at /home/michi/development/git/libreoffice/cppuhelper/source/implbase.cxx:79 #12 0x00007ff8bb84d6c5 in cppu::PartialWeakComponentImplHelper<com::sun:⭐:accessibility::XAccessibleContext2, com::sun:⭐:accessibility::XAccessibleEventBroadcaster>::release (this=0x558da6f7a220) at include/cppuhelper/compbase.hxx:86 #13 0x00007ff8bb8e0b95 in cppu::ImplInheritanceHelper<comphelper::OCommonAccessibleComponent, com::sun:⭐:accessibility::XAccessibleComponent>::release (this=0x558da6f7a220) at include/cppuhelper/implbase.hxx:171 #14 0x00007ff8bb97d595 in cppu::ImplInheritanceHelper<comphelper::OAccessibleComponentHelper, com::sun:⭐:accessibility::XAccessible>::release (this=0x558da6f7a220) at include/cppuhelper/implbase.hxx:171 #15 0x00007ff8af309baa in com::sun:⭐:uno::Reference<com::sun:⭐:accessibility::XAccessible>::~Reference (this=0x558da6f7a428) at include/com/sun/star/uno/Reference.hxx:114 #16 0x00007ff8af321bad in QtAccessibleWidget::~QtAccessibleWidget (this=0x558da6f7a3e0) at vcl/inc/qt6/../qt5/QtAccessibleWidget.hxx:39 #17 0x00007ff8af321c49 in QtAccessibleWidget::~QtAccessibleWidget (this=0x558da6f7a3e0) at vcl/inc/qt6/../qt5/QtAccessibleWidget.hxx:39 #18 0x00007ff8ad8faf48 in QAccessibleCache::deleteInterface (this=0x558d9fbd0ac0, id=2147483692, obj=0x558da6eecdb0) at /home/michi/development/git/qt5/qtbase/src/gui/accessible/qaccessiblecache.cpp:173 #19 0x00007ff8ad8fad78 in QAccessibleCache::~QAccessibleCache (this=0x558d9fbd0ac0) at /home/michi/development/git/qt5/qtbase/src/gui/accessible/qaccessiblecache.cpp:31 #20 0x00007ff8ad8faf8d in QAccessibleCache::~QAccessibleCache (this=0x558d9fbd0ac0) at /home/michi/development/git/qt5/qtbase/src/gui/accessible/qaccessiblecache.cpp:29 #21 0x00007ff8ad8fb027 in cleanupAccessibleCache () at /home/michi/development/git/qt5/qtbase/src/gui/accessible/qaccessiblecache.cpp:24 #22 0x00007ff8ae44a792 in qt_call_post_routines () at /home/michi/development/git/qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp:343 #23 0x00007ff8ac3ddee4 in QApplication::~QApplication (this=0x558d9e8c76c0) at /home/michi/development/git/qt5/qtbase/src/widgets/kernel/qapplication.cpp:667 #24 0x00007ff8ac3de29d in QApplication::~QApplication (this=0x558d9e8c76c0) at /home/michi/development/git/qt5/qtbase/src/widgets/kernel/qapplication.cpp:663 #25 0x00007ff8af3d63b8 in std::default_delete<QApplication>::operator() (this=0x558d9e955870, __ptr=0x558d9e8c76c0) at /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/unique_ptr.h:93 #26 0x00007ff8af3d7da8 in std::__uniq_ptr_impl<QApplication, std::default_delete<QApplication> >::reset (this=0x558d9e955870, __p=0x0) at /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/unique_ptr.h:205 #27 0x00007ff8af3cfcbd in std::unique_ptr<QApplication, std::default_delete<QApplication> >::reset (this=0x558d9e955870, __p=0x0) at /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/bits/unique_ptr.h:504 #28 0x00007ff8af3c7b34 in QtInstance::~QtInstance (this=0x558d9e9556e0) at vcl/qt6/../qt5/QtInstance.cxx:323 #29 0x00007ff8af3c7c29 in QtInstance::~QtInstance (this=0x558d9e9556e0) at vcl/qt6/../qt5/QtInstance.cxx:320 #30 0x00007ff8b9bb1c54 in DestroySalInstance (pInst=0x558d9e9556f0) at /home/michi/development/git/libreoffice/vcl/source/app/salplug.cxx:361 #31 0x00007ff8b9ca1509 in DeInitVCL () at /home/michi/development/git/libreoffice/vcl/source/app/svmain.cxx:629 #32 0x00007ff8b9c9fa4f in ImplSVMain () at /home/michi/development/git/libreoffice/vcl/source/app/svmain.cxx:241 #33 0x00007ff8b9ca15e9 in SVMain () at /home/michi/development/git/libreoffice/vcl/source/app/svmain.cxx:248 #34 0x00007ff8c2b9f4ba in soffice_main () at /home/michi/development/git/libreoffice/desktop/source/app/sofficemain.cxx:122 #35 0x0000558d9330ba6d in sal_main () at /home/michi/development/git/libreoffice/desktop/source/app/main.c:51 #36 0x0000558d9330ba47 in main (argc=2, argv=0x7ffd2669fb48) at /home/michi/development/git/libreoffice/desktop/source/app/main.c:49 Change-Id: Ifa7e18393edcc1889bcb390fa453c611d9345bdc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182174 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
209 lines
8.2 KiB
C++
209 lines
8.2 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <tools/color.hxx>
|
|
#include <vcl/image.hxx>
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <comphelper/accessiblecomponenthelper.hxx>
|
|
#include <comphelper/compbase.hxx>
|
|
#include <com/sun/star/accessibility/XAccessible.hpp>
|
|
#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
|
|
|
|
#include <mutex>
|
|
#include <vector>
|
|
|
|
#define VALUESET_ITEM_NONEITEM 0xFFFE
|
|
|
|
enum ValueSetItemType
|
|
{
|
|
VALUESETITEM_NONE,
|
|
VALUESETITEM_IMAGE,
|
|
VALUESETITEM_IMAGE_AND_TEXT,
|
|
VALUESETITEM_COLOR,
|
|
VALUESETITEM_USERDRAW
|
|
};
|
|
|
|
class ValueItemAcc;
|
|
class ValueSet;
|
|
|
|
struct ValueSetItem
|
|
{
|
|
ValueSet& mrParent;
|
|
OUString maText;
|
|
void* mpData;
|
|
rtl::Reference< ValueItemAcc > mxAcc;
|
|
Image maImage;
|
|
Color maColor;
|
|
sal_uInt16 mnId;
|
|
sal_uInt8 meType;
|
|
bool mbVisible;
|
|
|
|
explicit ValueSetItem( ValueSet& rParent );
|
|
~ValueSetItem();
|
|
|
|
const rtl::Reference<ValueItemAcc>& GetAccessible(bool bCreate = true);
|
|
};
|
|
|
|
class ValueSetAcc final
|
|
: public cppu::ImplInheritanceHelper<comphelper::OAccessibleComponentHelper,
|
|
css::accessibility::XAccessible,
|
|
css::accessibility::XAccessibleSelection>
|
|
{
|
|
public:
|
|
|
|
explicit ValueSetAcc(ValueSet* pValueSet);
|
|
virtual ~ValueSetAcc() override;
|
|
|
|
void FireAccessibleEvent( short nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue );
|
|
bool HasAccessibleListeners() const;
|
|
|
|
public:
|
|
|
|
/** Called by the corresponding ValueSet when it gets the focus.
|
|
Stores the new focus state and broadcasts a state change event.
|
|
*/
|
|
void GetFocus();
|
|
|
|
/** Called by the corresponding ValueSet when it loses the focus.
|
|
Stores the new focus state and broadcasts a state change event.
|
|
*/
|
|
void LoseFocus();
|
|
|
|
/** Called by the corresponding ValueSet when it gets destroyed. */
|
|
void Invalidate();
|
|
|
|
// XAccessible
|
|
virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
|
|
|
|
// XAccessibleContext
|
|
virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override;
|
|
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override;
|
|
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
|
|
virtual sal_Int64 SAL_CALL getAccessibleIndexInParent( ) override;
|
|
virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
|
|
virtual OUString SAL_CALL getAccessibleDescription( ) override;
|
|
virtual OUString SAL_CALL getAccessibleName( ) override;
|
|
virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
|
|
virtual sal_Int64 SAL_CALL getAccessibleStateSet( ) override;
|
|
virtual css::lang::Locale SAL_CALL getLocale( ) override;
|
|
|
|
// OCommonAccessibleComponent
|
|
virtual css::awt::Rectangle implGetBounds() override;
|
|
|
|
// XAccessibleComponent
|
|
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
|
|
virtual void SAL_CALL grabFocus( ) override;
|
|
virtual sal_Int32 SAL_CALL getForeground( ) override;
|
|
virtual sal_Int32 SAL_CALL getBackground( ) override;
|
|
|
|
// XAccessibleSelection
|
|
virtual void SAL_CALL selectAccessibleChild( sal_Int64 nChildIndex ) override;
|
|
virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int64 nChildIndex ) override;
|
|
virtual void SAL_CALL clearAccessibleSelection( ) override;
|
|
virtual void SAL_CALL selectAllAccessibleChildren( ) override;
|
|
virtual sal_Int64 SAL_CALL getSelectedAccessibleChildCount( ) override;
|
|
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex ) override;
|
|
virtual void SAL_CALL deselectAccessibleChild( sal_Int64 nSelectedChildIndex ) override;
|
|
|
|
private:
|
|
ValueSet* mpValueSet;
|
|
/// The current FOCUSED state.
|
|
bool mbIsFocused;
|
|
|
|
/** Return the number of items. This takes the None-Item into account.
|
|
*/
|
|
sal_uInt16 getItemCount() const;
|
|
|
|
/** Return the item associated with the given index. The None-Item is
|
|
taken into account which, when present, is taken to be the first
|
|
(with index 0) item.
|
|
@param nIndex
|
|
Index of the item to return. The index 0 denotes the None-Item
|
|
when present.
|
|
@return
|
|
Returns NULL when the given index is out of range.
|
|
*/
|
|
ValueSetItem* getItem (sal_uInt16 nIndex) const;
|
|
|
|
/** Check whether or not the object has been disposed (or is in the
|
|
state of being disposed). If that is the case then
|
|
DisposedException is thrown to inform the (indirect) caller of the
|
|
foul deed.
|
|
@param bCheckValueSet
|
|
Whether to also check that the ValueSet is non-null.
|
|
@throws css::lang::DisposedException
|
|
*/
|
|
void ThrowIfDisposed(bool bCheckValueSet = true);
|
|
|
|
/** Check whether the value set has a 'none' field, i.e. a field (button)
|
|
that deselects any items (selects none of them).
|
|
@return
|
|
Returns <true/> if there is a 'none' field and <false/> if it is
|
|
missing.
|
|
*/
|
|
bool HasNoneField() const;
|
|
};
|
|
|
|
class ValueItemAcc : public cppu::ImplInheritanceHelper<comphelper::OAccessibleComponentHelper,
|
|
css::accessibility::XAccessible>
|
|
{
|
|
private:
|
|
ValueSetItem* mpValueSetItem;
|
|
|
|
public:
|
|
|
|
ValueItemAcc(ValueSetItem* pValueSetItem);
|
|
virtual ~ValueItemAcc() override;
|
|
|
|
void ValueSetItemDestroyed();
|
|
|
|
void FireAccessibleEvent( short nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue );
|
|
|
|
public:
|
|
|
|
// XAccessible
|
|
virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override;
|
|
|
|
// XAccessibleContext
|
|
virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override;
|
|
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override;
|
|
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
|
|
virtual sal_Int64 SAL_CALL getAccessibleIndexInParent( ) override;
|
|
virtual sal_Int16 SAL_CALL getAccessibleRole( ) override;
|
|
virtual OUString SAL_CALL getAccessibleDescription( ) override;
|
|
virtual OUString SAL_CALL getAccessibleName( ) override;
|
|
virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
|
|
virtual sal_Int64 SAL_CALL getAccessibleStateSet( ) override;
|
|
virtual css::lang::Locale SAL_CALL getLocale( ) override;
|
|
|
|
// OCommonAccessibleComponent
|
|
virtual css::awt::Rectangle implGetBounds() override;
|
|
|
|
// XAccessibleComponent
|
|
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
|
|
virtual void SAL_CALL grabFocus( ) override;
|
|
virtual sal_Int32 SAL_CALL getForeground( ) override;
|
|
virtual sal_Int32 SAL_CALL getBackground( ) override;
|
|
};
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|