svtools/source/control/valueacc.cxx | 20 ++++++++++++-------- svtools/source/control/valueimp.hxx | 8 +++++++- svtools/source/control/valueset.cxx | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-)
New commits: commit 2f5e7a07775690e57d639eeca7a1e41733fa93a9 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Thu Sep 7 08:09:31 2023 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Thu Sep 7 13:13:18 2023 +0200 tdf#157092 a11y Let only drawing area dispose its ValueSet acc Don't dispose the a11y object in the `ValueSet` dtor, because it doesn't own its a11y object, but it is owned by the `weld::DrawingArea` of the `CustomWeld` that the `ValueSet` (as a sub-class of `CustomWidgetController`) belongs to. The `CustomWeld` ctor passes the a11y ref retrieved by `CustomWidgetController::createAccessible` to `weld_drawing_area`, which takes ownership and disposes the object. (For Gtk, see `GtkInstanceDrawingArea::~GtkInstanceDrawingArea`. For non-Gtk, see how the `SalInstanceDrawingArea` ctor passes the reference to `VclInstanceDrawingArea::SetAccessible`/ `vcl::Window::SetAccessible`, so it gets disposed when that `VclInstanceDrawingArea` gets disposed, s. `vcl::Window::dispose`.) Other classes derived from `CustomWidgetController` also don't dispose the a11y object themselves. Still reset the `ValueSet` pointer in `ValueSetAcc` to nullptr when the `ValueSet` gets destroyed and turn the check for a valid pointer from just an `OSL_ASSERT` to a real assert and throwing a `RuntimeException`. But still allow getting the a11y context when only the ValueSet has been deleted but the object has not been disposed yet. Fixes a crash due to a `com::sun::star::lang::DisposedException` being thrown when using the new search feature in the "Tools" -> "Options" dialog (or when just switching to the "LibreOfficeDev Writer/Web" -> "Background" page with the qt6 VCL plugin or on Windows when the NVDA screen reader is running. This happens when the drawing area is hidden and the a11y layer is meant to be notified about this (so the a11y object can be removed). It still seems a bit odd that the `ValueSet` gets destroyed (in `SvxColorTabPage::~SvxColorTabPage`, frame 20 in below backtrace) before the corresponding `vcl::Window` gets hidden (in the base class dtor, `SfxTabPage::~SfxTabPage`, s. frame 19 in the backtrace). Backtrace for how the exception gets thrown: 1 com::sun::star::lang::DisposedException::DisposedException DisposedException.hpp 40 0x7fa385fd9ca9 2 ValueSetAcc::ThrowIfDisposed valueacc.cxx 956 0x7fa385fd9342 3 ValueSetAcc::getAccessibleContext valueacc.cxx 473 0x7fa385fd69fa 4 VCLXAccessibleComponent::ProcessWindowChildEvent vclxaccessiblecomponent.cxx 186 0x7fa3853dc905 5 VCLXAccessibleComponent::WindowChildEventListener vclxaccessiblecomponent.cxx 124 0x7fa3853dc51d 6 VCLXAccessibleComponent::LinkStubWindowChildEventListener vclxaccessiblecomponent.cxx 114 0x7fa3853dc43f 7 Link<VclWindowEvent&, void>::Call link.hxx 111 0x7fa382c56ccf 8 vcl::Window::CallEventListeners event.cxx 296 0x7fa382c53e5b 9 vcl::Window::ImplResetReallyVisible stacking.cxx 719 0x7fa382b51a49 10 vcl::Window::ImplResetReallyVisible stacking.cxx 735 0x7fa382b51b0e 11 vcl::Window::ImplResetReallyVisible stacking.cxx 735 0x7fa382b51b0e 12 vcl::Window::ImplResetReallyVisible stacking.cxx 735 0x7fa382b51b0e 13 vcl::Window::ImplResetReallyVisible stacking.cxx 735 0x7fa382b51b0e 14 vcl::Window::ImplResetReallyVisible stacking.cxx 735 0x7fa382b51b0e 15 vcl::Window::ImplResetReallyVisible stacking.cxx 735 0x7fa382b51b0e 16 vcl::Window::Show window.cxx 2234 0x7fa382d94f7c 17 vcl::Window::Hide window.hxx 880 0x7fa382b23600 18 SalInstanceContainer::move salvtables.cxx 1352 0x7fa3834789f3 19 SfxTabPage::~SfxTabPage tabdlg.cxx 157 0x7fa38928ab47 20 SvxColorTabPage::~SvxColorTabPage tpcolor.cxx 166 0x7fa350950d3e 21 SvxColorTabPage::~SvxColorTabPage tpcolor.cxx 166 0x7fa350950d5a 22 std::default_delete<SfxTabPage>::operator() unique_ptr.h 99 0x7fa350538fdc 23 std::__uniq_ptr_impl<SfxTabPage, std::default_delete<SfxTabPage>>::reset unique_ptr.h 211 0x7fa35080dcbe 24 std::unique_ptr<SfxTabPage, std::default_delete<SfxTabPage>>::reset unique_ptr.h 509 0x7fa350808555 25 SvxAreaTabPage::SetOptimalSize tparea.cxx 155 0x7fa35093db3e 26 SvxBkgTabPage::Create backgrnd.cxx 230 0x7fa350864dbc 27 SwModule::CreateTabPage appopt.cxx 509 0x7fa339e10973 28 OfaTreeOptionsDialog::SelectHdl_Impl treeopt.cxx 1335 0x7fa3507f947a 29 OfaTreeOptionsDialog::ShowPageHdl_Impl treeopt.cxx 625 0x7fa3507f4782 30 OfaTreeOptionsDialog::LinkStubShowPageHdl_Impl treeopt.cxx 623 0x7fa3507f4763 31 Link<weld::TreeView&, void>::Call link.hxx 111 0x7fa3834b18f1 32 weld::TreeView::signal_changed weld.hxx 953 0x7fa3834aa10d 33 SalInstanceTreeView::SelectHdl salvtables.cxx 5276 0x7fa38349363e 34 SalInstanceTreeView::LinkStubSelectHdl salvtables.cxx 5272 0x7fa3834935fb 35 Link<SvTreeListBox *, void>::Call link.hxx 111 0x7fa382b8a339 36 SvTreeListBox::SelectHdl treelistbox.cxx 452 0x7fa38307f5c2 37 SvTreeListBox::Select treelistbox.cxx 2111 0x7fa383085b4a 38 SvImpLBox::SetCursor svimpbox.cxx 614 0x7fa3830a66c3 39 ImpLBSelEng::SetCursorAtPoint svimpbox.cxx 2575 0x7fa3830aeaa8 40 SelectionEngine::SelMouseButtonDown seleng.cxx 172 0x7fa382d09354 41 SvImpLBox::MouseButtonDown svimpbox.cxx 2004 0x7fa3830ac9f8 42 SvTreeListBox::MouseButtonDown treelistbox.cxx 2260 0x7fa383086422 43 ImplHandleMouseEvent winproc.cxx 707 0x7fa382daed00 44 ImplHandleSalMouseButtonDown winproc.cxx 2340 0x7fa382db5c5d 45 ImplWindowFrameProc winproc.cxx 2685 0x7fa382db6f7e 46 SalFrame::CallCallback salframe.hxx 310 0x7fa378ca4edc 47 QtFrame::CallCallback QtFrame.hxx 230 0x7fa378ca6418 48 QtWidget::handleMouseButtonEvent QtWidget.cxx 181 0x7fa378cf959b 49 QtWidget::mousePressEvent QtWidget.cxx 186 0x7fa378cf95f3 50 QWidget::event qwidget.cpp 8978 0x7fa376a2f327 51 QtWidget::event QtWidget.cxx 730 0x7fa378cfb2f6 52 QApplicationPrivate::notify_helper qapplication.cpp 3287 0x7fa3769a666a 53 QApplication::notify qapplication.cpp 2774 0x7fa3769a4539 54 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1125 0x7fa3783a5ed0 55 QCoreApplication::sendSpontaneousEvent qcoreapplication.cpp 1573 0x7fa3783a6a1d 56 QApplicationPrivate::sendMouseEvent qapplication.cpp 2358 0x7fa3769a31a2 57 QWidgetWindow::handleMouseEvent qwidgetwindow.cpp 627 0x7fa376a5f7cb 58 QWidgetWindow::event qwidgetwindow.cpp 241 0x7fa376a5dcfd 59 QApplicationPrivate::notify_helper qapplication.cpp 3287 0x7fa3769a666a 60 QApplication::notify qapplication.cpp 3238 0x7fa3769a647a 61 QCoreApplication::notifyInternal2 qcoreapplication.cpp 1125 0x7fa3783a5ed0 62 QCoreApplication::sendSpontaneousEvent qcoreapplication.cpp 1573 0x7fa3783a6a1d 63 QGuiApplicationPrivate::processMouseEvent qguiapplication.cpp 2315 0x7fa3775f21cd 64 QGuiApplicationPrivate::processWindowSystemEvent qguiapplication.cpp 2061 0x7fa3775f15cf 65 QWindowSystemInterface::sendWindowSystemEvents qwindowsysteminterface.cpp 1109 0x7fa37769ce23 66 xcbSourceDispatch qxcbeventdispatcher.cpp 57 0x7fa376064df7 67 ?? 0x7fa37df2b5b4 68 ?? 0x7fa37df2e607 69 g_main_context_iteration 0x7fa37df2ebfc 70 QEventDispatcherGlib::processEvents qeventdispatcher_glib.cpp 395 0x7fa3787b6b33 71 QXcbGlibEventDispatcher::processEvents qxcbeventdispatcher.cpp 96 0x7fa37606502c 72 QtInstance::ImplYield QtInstance.cxx 421 0x7fa378cc7502 73 QtInstance::DoYield QtInstance.cxx 432 0x7fa378cc762b 74 ImplYield svapp.cxx 372 0x7fa3835220ea 75 Application::Yield svapp.cxx 456 0x7fa383522e88 76 Dialog::Execute dialog.cxx 1078 0x7fa382c063e1 77 SalInstanceDialog::run salvtables.cxx 1877 0x7fa38347c313 78 weld::DialogController::run weld.hxx 2659 0x7fa3504a26e6 79 OfaTreeOptionsDialog::run treeopt.cxx 2587 0x7fa3508035fd 80 CuiAbstractController_Impl::Execute dlgfact.cxx 144 0x7fa35069d829 81 SfxApplication::OfaExec_Impl appserv.cxx 1463 0x7fa388faf85e 82 SfxStubSfxApplicationOfaExec_Impl sfxslots.hxx 1309 0x7fa388f88faf 83 SfxDispatcher::Call_Impl dispatch.cxx 254 0x7fa3890bfb4a 84 SfxDispatcher::Execute_ dispatch.cxx 753 0x7fa3890c31f4 85 SfxBindings::Execute_Impl bindings.cxx 1061 0x7fa3890aefa0 86 SfxDispatchController_Impl::dispatch unoctitm.cxx 688 0x7fa389185ba6 87 SfxOfficeDispatch::dispatch unoctitm.cxx 250 0x7fa389183867 88 framework::MenuBarManager::Select menubarmanager.cxx 827 0x7fa38a7e2dff 89 framework::MenuBarManager::LinkStubSelect menubarmanager.cxx 791 0x7fa38a7e2ab7 90 Link<Menu *, bool>::Call link.hxx 111 0x7fa382cb0337 91 Menu::Select menu.cxx 358 0x7fa382ca1c90 92 Menu::ImplCallSelect menu.cxx 2135 0x7fa382caa907 93 Menu::LinkStubImplCallSelect menu.cxx 2132 0x7fa382caa8d9 94 Link<void *, void>::Call link.hxx 111 0x7fa382db870d 95 ImplHandleUserEvent winproc.cxx 2287 0x7fa382db57ca 96 ImplWindowFrameProc winproc.cxx 2851 0x7fa382db76f7 97 SalFrame::CallCallback salframe.hxx 310 0x7fa378ca4edc 98 QtInstance::ProcessEvent QtInstance.cxx 484 0x7fa378cc799b 99 operator() salusereventlist.cxx 119 0x7fa383465b7b 100 SalUserEventList::DispatchUserEvents salusereventlist.cxx 120 0x7fa383465e4f 101 QtInstance::ImplYield QtInstance.cxx 410 0x7fa378cc7480 102 QtInstance::DoYield QtInstance.cxx 432 0x7fa378cc762b 103 ImplYield svapp.cxx 372 0x7fa3835220ea 104 Application::Yield svapp.cxx 456 0x7fa383522e88 105 Application::Execute svapp.cxx 350 0x7fa383521ddd 106 desktop::Desktop::Main app.cxx 1601 0x7fa38ca36276 107 ImplSVMain svmain.cxx 204 0x7fa383541e84 108 SVMain svmain.cxx 236 0x7fa383541fb9 109 soffice_main sofficemain.cxx 94 0x7fa38caa1b5d 110 sal_main main.c 51 0x5568fd6859d4 111 main main.c 49 0x5568fd6859ba Change-Id: I247648a7a707f02bf1fdd339d3c329694636d835 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156645 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/svtools/source/control/valueacc.cxx b/svtools/source/control/valueacc.cxx index cdf759621042..2f897ae015ce 100644 --- a/svtools/source/control/valueacc.cxx +++ b/svtools/source/control/valueacc.cxx @@ -29,6 +29,7 @@ #include <com/sun/star/accessibility/AccessibleRole.hpp> #include <com/sun/star/accessibility/AccessibleStateType.hpp> #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> using namespace ::com::sun::star; @@ -470,7 +471,8 @@ void ValueSetAcc::LoseFocus() uno::Reference< accessibility::XAccessibleContext > SAL_CALL ValueSetAcc::getAccessibleContext() { - ThrowIfDisposed(); + // still allow retrieving a11y context when not disposed yet, but ValueSet is unset + ThrowIfDisposed(false); return this; } @@ -886,16 +888,16 @@ void SAL_CALL ValueSetAcc::deselectAccessibleChild( sal_Int64 nChildIndex ) mpParent->SetNoSelection(); } +void ValueSetAcc::Invalidate() +{ + mpParent = nullptr; +} void ValueSetAcc::disposing(std::unique_lock<std::mutex>& rGuard) { // Make a copy of the list and clear the original. ::std::vector<uno::Reference<accessibility::XAccessibleEventListener> > aListenerListCopy = std::move(mxEventListeners); - // Reset the pointer to the parent. It has to be the one who has - // disposed us because he is dying. - mpParent = nullptr; - if (aListenerListCopy.empty()) return; @@ -946,7 +948,7 @@ ValueSetItem* ValueSetAcc::getItem (sal_uInt16 nIndex) const } -void ValueSetAcc::ThrowIfDisposed() +void ValueSetAcc::ThrowIfDisposed(bool bCheckParent) { if (m_bDisposed) { @@ -955,9 +957,11 @@ void ValueSetAcc::ThrowIfDisposed() "object has been already disposed", getXWeak()); } - else + + if (bCheckParent && !mpParent) { - DBG_ASSERT (mpParent!=nullptr, "ValueSetAcc not disposed but mpParent == NULL"); + assert(false && "ValueSetAcc not disposed but mpParent == NULL"); + throw css::uno::RuntimeException("ValueSetAcc not disposed but mpParent == NULL"); } } diff --git a/svtools/source/control/valueimp.hxx b/svtools/source/control/valueimp.hxx index ed34aa35995b..fca4e438f72f 100644 --- a/svtools/source/control/valueimp.hxx +++ b/svtools/source/control/valueimp.hxx @@ -97,6 +97,9 @@ public: */ 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; @@ -167,9 +170,12 @@ private: 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 (parent) + is non-null. @throws css::lang::DisposedException */ - void ThrowIfDisposed(); + void ThrowIfDisposed(bool bCheckParent = true); /** Check whether the value set has a 'none' field, i.e. a field (button) that deselects any items (selects none of them). diff --git a/svtools/source/control/valueset.cxx b/svtools/source/control/valueset.cxx index e40da6193084..89ce7f8cdb23 100644 --- a/svtools/source/control/valueset.cxx +++ b/svtools/source/control/valueset.cxx @@ -124,7 +124,7 @@ Reference<XAccessible> ValueSet::CreateAccessible() ValueSet::~ValueSet() { if (mxAccessible) - mxAccessible->dispose(); + mxAccessible->Invalidate(); ImplDeleteItems(); }