tdf#160837 qt a11y: Don't report window role for non-top-level

Quoting from offapi/com/sun/star/accessibility/AccessibleRole.idl,
AccessibleRole::Frame is for:

> A top level window with a title bar, border, menu bar, etc.
> It is often used as the primary window for an application.

However, the FRAME role also gets used for frames that
are not actually top-levels at least with the Qt-based
VCL plugins, where there is an object of role FRAME as a
child of the actual top-level for e.g. the Writer main
window. (The actual top-level is a QtMainWindow.)
That frame contains the window content starting right
below the (native) menu bar.

Mapping the AccessibleRole::FRAME a11y role to
the Qt equivalent QAccessible::Window would result
in window-relative positions reported via AT-SPI
to be relative to that frame, instead of the actual
top-level, s. the implementation in qtbase's
AtSpiAdaptor::translateFromScreenCoordinates [1]
which calculates the relative position to the
first top-level in its a11y hierarchy.

This resulted in Accerciser's highlighting of the
currently selected object to be too far up, as the
"window-relative position" was missing the menu
bar height in the y coordinate when window-relative
positions are used, which is the case on Wayland,
s.a. the commit message of

    commit a499874d9c
    Author: Michael Weghorn <m.weghorn@posteo.de>
    Date:   Thu Sep 26 18:22:12 2024 +0200

        tdf#160837 qt: Rely on toolkit for frame positions, drop menubar hack

for more background.

To fix this, prevent reporting an invalid top-level
window role for frames that are not actually top-levels:
When mapping AccessibleRole::FRAME to a corresponding
Qt a11y role, take into account whether the
frame still has another (real) top-level window as a parent.

This makes the highlighted area in Accerciser become correct
when using LO with the qt6 VCL plugin and Accerciser with
ACCERCISER_WINDOW_MANAGER=kwin in a KDE Plasma Wayland session.

The same would generally make sense for
AccessibleRole::DIALOG. However, there that
would currently result in the additional
semantics of this being a dialog (not
another kind of top-level window) getting lost
when doing so. As dialogs usually don't have a separate
menu bar, at least the incorrect reporting of window-relative positions
is less relevant.

Leave dialog unchanged for now, maybe reconsider later
as needed.

Ultimately, using native Qt widgets for dialogs (see tdf#130857)
should presumably fix the underlying problem of the extra frame
on VCL side being used altogether.

[1] https://code.qt.io/cgit/qt/qtbase.git/tree/src/gui/accessible/linux/atspiadaptor.cpp?id=da4a6cf78ff42a4f69c2775997ff174ef647f3f3#n2401

Change-Id: I5ae066bd996f042b370b067a30213d3a1045480e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174350
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Tested-by: Jenkins
This commit is contained in:
Michael Weghorn 2024-10-01 15:24:25 +02:00
parent 885c0b1948
commit dd58b893f0

View file

@ -431,7 +431,16 @@ QAccessible::Role QtAccessibleWidget::role() const
return QAccessible::Footer;
case AccessibleRole::FOOTNOTE:
return QAccessible::Note;
case AccessibleRole::FRAME: // top-level window with title bar
case AccessibleRole::FRAME:
// report Pane instead of Window role for a frame that's not actually
// an accessible frame (top-level window with title bar) itself,
// but a child of the real top-level
if (QAccessibleInterface* pParent = parent())
{
const QAccessible::Role eParentRole = pParent->role();
if (eParentRole == QAccessible::Window || eParentRole == QAccessible::Dialog)
return QAccessible::Pane;
}
return QAccessible::Window;
case AccessibleRole::GLASS_PANE:
return QAccessible::UserRole;