a11y atspi: Don't restrict top-level window to 2 a11y roles

So far, only accessible interfaces of roles QAccessible::Dialog
and QAccessible::Window were taken into account when trying to
find the top-level window in order to calculate the window-relative
coordinates relative to that one.

However, an app doesn't necessarily need to have any such widget/
window as it's top-level object, but can have any widget there.
Therefore, consider any a11y object that is a direct child of the
application's a11y object a top-level window as well.

For example, in the spinboxes example
(qtbase/examples/widgets/widgets/spinboxes/spinboxes), the top-level
widget is a QGroupBox, which has an accessible role of QAccessible::Client,
which maps to ATSPI_ROLE_FILLER for AT-SPI on Linux.

Since that's the top-level widget, window-relative coordinates
should be calculated relative to it.
(Without this change in place, screen coordinates would be
used for the window-relative coordinates as well, as found by
the script attached to QTBUG-106527.)

Also deduplicate a bit and just have a single loop instead
of the extra check on the interface itself at the beginning.

Fixes: QTBUG-106527
Pick-to: 6.6 6.5
Change-Id: I8d2a00bcc22c71d696e4f48233afddc80e93bc1b
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Michael Weghorn 2023-10-02 23:09:06 +02:00
parent 78cb91c5ca
commit 1b0e76f514

View File

@ -1750,15 +1750,14 @@ bool AtSpiAdaptor::inheritsQAction(QObject *object)
// Component
static QAccessibleInterface * getWindow(QAccessibleInterface * interface)
{
if (interface->role() == QAccessible::Dialog || interface->role() == QAccessible::Window)
// find top-level window in a11y hierarchy (either has a
// corresponding role or is a direct child of the application object)
QAccessibleInterface* app = QAccessible::queryAccessibleInterface(qApp);
while (interface && interface->role() != QAccessible::Dialog
&& interface->role() != QAccessible::Window && interface->parent() != app)
interface = interface->parent();
return interface;
QAccessibleInterface * parent = interface->parent();
while (parent && parent->role() != QAccessible::Dialog
&& parent->role() != QAccessible::Window)
parent = parent->parent();
return parent;
}
bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)