By default, a vcl::Window's XAccessible is its
VCLXWindow (toolkit peer):
css::uno::Reference< css::accessibility::XAccessible > Window::CreateAccessible()
{
css::uno::Reference< css::accessibility::XAccessible > xAcc( GetComponentInterface(), css::uno::UNO_QUERY );
return xAcc;
}
However, that's a virtual method and subclasses can
return a different XAccessible.
MenuFloatingWindow::CreateAccessible returns the
accessible of its menu.
However, winaccessibility's AccTopWindowListener
code was relying on the Window's XAccessible always
being its VCLXWindow.
The VLCXWindow is passed as a param in the
XTopWindowListener methods, and AccTopWindowListener
was querying it for the XAccessible interface, and
then calling XAccessible::getAccessibleContext in
order to retrieve the XAccessibleContext for the
window.
This is incorrect if the Window actually has another
XAccessible.
For the df#164093 scenario with NVDA running, opening and
closing the sidebar popup menu would result in the
VCLXWindow's VCLXWindow::getAccessibleContext menu
getting called, which calls VCLXWindow::CreateAccessibleContext
and the VCLXWindow would keep a reference to the
returned XAccessibleContext and dispose it when
the VLCXWindow itself gets disposed.
However, AccessibleFactory::createAccessibleContext
(called by VCLXWindow::CreateAccessibleContext)
doesn't actually create a new object for the
MenuFloatingWindow's accessible, but returns the
existing accessible object of the PopupMenu, which is
owned by the PopupMenu, not the MenuFloatingWindow,
s.a. previous commit
Change-Id: Ia2931bee23204395e8b3396927acf4fa1d0f077c
Author: Michael Weghorn <m.weghorn@posteo.de>
Date: Thu Dec 5 11:06:48 2024 +0000
tdf#164093 tdf#157001 a11y: Improve menu window disposal
for more details.
Backtrace of how that accessible context was returned:
1 `anonymous namespace'::AccessibleFactory::createAccessibleContext acc_factory.cxx 305 0x7fffbc160767
2 VCLXWindow::CreateAccessibleContext vclxwindow.cxx 879 0x7fffc0b1bc67
3 VCLXWindow::getAccessibleContext vclxwindow.cxx 2418 0x7fffc0b2670b
4 AccTopWindowListener::HandleWindowOpened AccTopWindowListener.cxx 60 0x7fffe5c32ab6
5 AccTopWindowListener::windowOpened AccTopWindowListener.cxx 119 0x7fffe5c3375e
6 ``anonymous namespace'::VCLXToolkit::callTopWindowListeners'::`2'::<lambda_1>::operator() vclxtoolkit.cxx 2364 0x7fffc0af27ef
7 comphelper::OInterfaceContainerHelper4<com::sun::star::awt::XTopWindowListener>::forEach<``anonymous namespace'::VCLXToolkit::callTopWindowListeners'::`2'::<lambda_1>> interfacecontainer4.hxx 349 0x7fffc0ae7f9e
8 `anonymous namespace'::VCLXToolkit::callTopWindowListeners vclxtoolkit.cxx 2359 0x7fffc0afeaed
9 `anonymous namespace'::VCLXToolkit::eventListenerHandler vclxtoolkit.cxx 2295 0x7fffc0b02492
10 `anonymous namespace'::VCLXToolkit::LinkStubeventListenerHandler vclxtoolkit.cxx 2288 0x7fffc0afbdf6
11 Link<VclSimpleEvent &,void>::Call link.hxx 111 0x7fffbfba33d3
12 VclEventListeners::Call vclevent.cxx 47 0x7fffbfba35f1
13 Application::ImplCallEventListeners svapp.cxx 733 0x7fffbfb76dbb
14 vcl::Window::CallEventListeners event.cxx 229 0x7fffbf45f841
15 vcl::Window::ImplSetReallyVisible window.cxx 1331 0x7fffbf566bad
16 vcl::Window::ImplSetReallyVisible window.cxx 1344 0x7fffbf566c7d
17 vcl::Window::Show window.cxx 2336 0x7fffbf56a8d1
18 vcl::Window::Show window.cxx 2349 0x7fffbf56a9ce
19 FloatingWindow::StartPopupMode floatwin.cxx 825 0x7fffbf46a702
20 PopupMenu::Run menu.cxx 3018 0x7fffbf4a6f02
... <More>
When the MenuFloatingWindow gets disposed, its
VCLXWindow is also disposed. Since it incorrectly
assumes it (or its Window) owns the XAccessibleContext,
it disposes that as well:
1 OAccessibleMenuBaseComponent::disposing accessiblemenubasecomponent.cxx 608 0x7fffbf300c82
2 cppu::WeakComponentImplHelperBase::dispose implbase.cxx 104 0x7fffe199964a
3 cppu::PartialWeakComponentImplHelper<com::sun::star::accessibility::XAccessibleContext2,com::sun::star::accessibility::XAccessibleEventBroadcaster>::dispose compbase.hxx 90 0x7fffdb8d1820
4 VCLXWindow::dispose vclxwindow.cxx 938 0x7fffc0b24012
5 UnoWrapper::WindowDestroyed unowrapper.cxx 302 0x7fffc0cfddc6
6 vcl::Window::dispose window.cxx 220 0x7fffbf56e68f
7 SystemWindow::dispose syswin.cxx 107 0x7fffbf515606
8 FloatingWindow::dispose floatwin.cxx 225 0x7fffbf46b751
9 MenuFloatingWindow::dispose menufloatingwindow.cxx 134 0x7fffbf4bd766
10 VclReferenceBase::disposeOnce vclreferencebase.cxx 39 0x7fffbf7520d9
11 VclPtr<vcl::Window>::disposeAndClear vclptr.hxx 207 0x7fffbf3f98d2
12 PopupMenu::ImplExecute menu.cxx 2947 0x7fffbf4a0ee7
13 PopupMenu::Execute menu.cxx 2834 0x7fffbf49c392
14 MenuButton::ExecuteMenu menubtn.cxx 77 0x7fffbf639f1d
15 MenuButton::MouseButtonDown menubtn.cxx 214 0x7fffbf63a847
16 ImplHandleMouseEvent winproc.cxx 708 0x7fffbf57ca27
17 ImplHandleSalMouseButtonDown winproc.cxx 2338 0x7fffbf57e1af
18 ImplWindowFrameProc winproc.cxx 2683 0x7fffbf57fc07
19 SalFrame::CallCallback salframe.hxx 312 0x7fffbf3443c6
20 ImplHandleMouseMsg salframe.cxx 3415 0x7fffbc818e8f
... <More>
However, the Menu that actually owns the accessible may
still be alive, and then opening the menu again results
in an attempt to make use of the already disposed object,
triggering a crash due to a DisposedException being thrown:
1 RaiseException KERNELBASE 0x7ff808e8b699
2 CxxThrowException VCRUNTIME140 0x7fffef535267
3 comphelper::OCommonAccessibleComponent::ensureAlive accessiblecomponenthelper.cxx 141 0x7fffdb8d1937
4 comphelper::OContextEntryGuard::OContextEntryGuard accessiblecontexthelper.hxx 64 0x7fffbf2fb8eb
5 comphelper::OExternalLockGuard::OExternalLockGuard accessiblecontexthelper.hxx 81 0x7fffbf2fb948
6 OAccessibleMenuBaseComponent::getAccessibleContext accessiblemenubasecomponent.cxx 641 0x7fffbf301337
7 VCLXAccessibleComponent::ProcessWindowChildEvent vclxaccessiblecomponent.cxx 165 0x7fffc0a9596d
8 VCLXAccessibleComponent::WindowChildEventListener vclxaccessiblecomponent.cxx 124 0x7fffc0a96669
9 VCLXAccessibleComponent::LinkStubWindowChildEventListener vclxaccessiblecomponent.cxx 114 0x7fffc0a957f6
10 Link<VclWindowEvent &,void>::Call link.hxx 111 0x7fffbf45f7d3
11 vcl::Window::CallEventListeners event.cxx 300 0x7fffbf45fe0c
12 vcl::Window::ImplSetReallyVisible window.cxx 1331 0x7fffbf566bad
13 vcl::Window::ImplSetReallyVisible window.cxx 1344 0x7fffbf566c7d
14 vcl::Window::Show window.cxx 2336 0x7fffbf56a8d1
15 vcl::Window::Show window.cxx 2349 0x7fffbf56a9ce
16 FloatingWindow::StartPopupMode floatwin.cxx 825 0x7fffbf46a702
17 PopupMenu::Run menu.cxx 3018 0x7fffbf4a6f02
18 PopupMenu::ImplExecute menu.cxx 3005 0x7fffbf4a1707
19 PopupMenu::Execute menu.cxx 2834 0x7fffbf49c392
20 MenuButton::ExecuteMenu menubtn.cxx 77 0x7fffbf639f1d
... <More>
To fix that, adjust winaccessibility's
AccTopWindowListener to no longer just use
the VCLXWindow for the accessible, but
get the vcl::Window for the VCLXWindow and
query it's actual XAccessible using
vcl::Window::GetAccessible().
This fixes the tdf#164093 crash. The problem of
tdf#157001 where items in the popup menu of Calc's organize
template dialog are only announced the first time the menu
is opened still remains for now, but is also somehow
related to the MenuFloatingWindow being disposed.
(No longer reproducible when no longer calling
the base class FloatingWindow::dispose from
MenuFloatingWindow::dispose in a local test,
still needs further analysis.)
Change-Id: Ic96d2c95128af144c7769aac40707299b1c80f8c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177889
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
LibreOffice
LibreOffice is an integrated office suite based on copyleft licenses and compatible with most document formats and standards. Libreoffice is backed by The Document Foundation, which represents a large independent community of enterprises, developers and other volunteers moved by the common goal of bringing to the market the best software for personal productivity. LibreOffice is open source, and free to download, use and distribute.
A quick overview of the LibreOffice code structure.
Overview
You can develop for LibreOffice in one of two ways, one recommended and one much less so. First the somewhat less recommended way: it is possible to use the SDK to develop an extension, for which you can read the API docs and Developers Guide. This re-uses the (extremely generic) UNO APIs that are also used by macro scripting in StarBasic.
The best way to add a generally useful feature to LibreOffice is to work on the code base however. Overall this way makes it easier to compile and build your code, it avoids any arbitrary limitations of our scripting APIs, and in general is far more simple and intuitive - if you are a reasonably able C++ programmer.
The Build Chain and Runtime Baselines
These are the current minimal operating system and compiler versions to run and compile LibreOffice, also used by the TDF builds:
- Windows:
- Runtime: Windows 7
- Build: Cygwin + Visual Studio 2019 version 16.10
- macOS:
- Runtime: 10.15
- Build: 12 (13 for aarch64) + Xcode 14
- Linux:
- Runtime: RHEL 8 or CentOS 8 and comparable
- Build: either GCC 12; or Clang 12 with libstdc++ 10
- iOS (only for LibreOfficeKit):
- Runtime: 11.4 (only support for newer i devices == 64 bit)
- Build: Xcode 9.3 and iPhone SDK 11.4
- Android:
- Build: NDK r23 and SDK 30.0.3
- Emscripten / WASM:
- Runtime: a browser with SharedMemory support (threads + atomics)
- Build: Qt 5.15 with Qt supported Emscripten 1.39.8
- See README.wasm
Java is required for building many parts of LibreOffice. In TDF Wiki article Development/Java, the exact modules that depend on Java are listed.
The baseline for Java is Java Development Kit (JDK) Version 17 or later.
The baseline for Python is version 3.11. It follows the version available in SUSE Linux Enterprise Desktop and the Maintenance Support version of Red Hat Enterprise Linux.
If you want to use Clang with the LibreOffice compiler plugins, the minimal version of Clang is 12.0.1. Since Xcode doesn't provide the compiler plugin headers, you have to compile your own Clang to use them on macOS.
You can find the TDF configure switches in the distro-configs/ directory.
To setup your initial build environment on Windows and macOS, we provide the LibreOffice Development Environment (LODE) scripts.
For more information see the build instructions for your platform in the TDF wiki.
The Important Bits of Code
Each module should have a README.md file inside it which has some
degree of documentation for that module; patches are most welcome to
improve those. We have those turned into a web page here:
However, there are two hundred modules, many of them of only peripheral interest for a specialist audience. So - where is the good stuff, the code that is most useful. Here is a quick overview of the most important ones:
| Module | Description |
|---|---|
| sal/ | this provides a simple System Abstraction Layer |
| tools/ | this provides basic internal types: Rectangle, Color etc. |
| vcl/ | this is the widget toolkit library and one rendering abstraction |
| framework/ | UNO framework, responsible for building toolbars, menus, status bars, and the chrome around the document using widgets from VCL, and XML descriptions from /uiconfig/ files |
| sfx2/ | legacy core framework used by Writer/Calc/Draw: document model / load/save / signals for actions etc. |
| svx/ | drawing model related helper code, including much of Draw/Impress |
Then applications
| Module | Description |
|---|---|
| desktop/ | this is where the main() for the application lives, init / bootstrap. the name dates back to an ancient StarOffice that also drew a desktop |
| sw/ | Writer |
| sc/ | Calc |
| sd/ | Draw / Impress |
There are several other libraries that are helpful from a graphical perspective:
| Module | Description |
|---|---|
| basegfx/ | algorithms and data-types for graphics as used in the canvas |
| canvas/ | new (UNO) canvas rendering model with various backends |
| cppcanvas/ | C++ helper classes for using the UNO canvas |
| drawinglayer/ | View code to render drawable objects and break them down into primitives we can render more easily. |
Rules for #include Directives (C/C++)
Use the "..." form if and only if the included file is found next to the
including file. Otherwise, use the <...> form. (For further details, see the
mail Re: C[++]: Normalizing include syntax ("" vs
<>).)
The UNO API include files should consistently use double quotes, for the benefit of external users of this API.
loplugin:includeform (compilerplugins/clang/includeform.cxx) enforces these rules.
Finding Out More
Beyond this, you can read the README.md files, send us patches, ask
on the mailing list libreoffice@lists.freedesktop.org (no subscription
required) or poke people on IRC #libreoffice-dev on irc.libera.chat -
we're a friendly and generally helpful mob. We know the code can be
hard to get into at first, and so there are no silly questions.
SAST Tools
PVS-Studio - static analyzer for C, C++, C#, and Java code.