diff options
author | Michael Weghorn <m.weghorn@posteo.de> | 2022-08-03 07:42:10 +0200 |
---|---|---|
committer | Michael Weghorn <m.weghorn@posteo.de> | 2022-08-17 10:48:59 +0200 |
commit | a32a3aa388534f67da02fd7f15a59648637bd753 (patch) | |
tree | 5e631d3b4f5ba9001f6396ab67c4f05dc949de17 /src | |
parent | 4d6decf628af9b19ed6381cc2fa9b91823c47bca (diff) | |
download | qtbase-a32a3aa388534f67da02fd7f15a59648637bd753.tar.gz |
a11y atspi: Add support for ATSPI_COORD_TYPE_PARENT
So far, only screen coordinates (`ATSPI_COORD_TYPE_SCREEN`)
and coordinates relative to the widget's top-level window
(`ATSPI_COORD_TYPE_WINDOW`) were supported.
In at-spi 2.30, a third coordinate type, describing
coordinates relative to the widget's immediate parent,
was added: `ATSPI_COORD_TYPE_PARENT` (commit: [1])
This commit adds the handling to convert to and
from that coord type as well and unifies the
existing handling to convert to/from screen coordinates
by introducing two static helper methods
(`AtSpiAdaptor::translateToScreenCoordinates` and
`AtSpiAdaptor::translateFromScreenCoordinates`) and
making use of those wherever conversion needs to
be done.
In addition, also add a check to only handle
requests using a coordinate type that is one of those
that is actually supported instead of returning
incorrect values (for the case that new coord types
should be introduced in AT-SPI in the future).
[1] https://gitlab.gnome.org/GNOME/at-spi2-core/-/commit/737c9853b681fb20fda79b32ed92cda96b381dd0
Fixes: QTBUG-105313
Change-Id: Ia8752bd6a35328cc2de33ecad08f2964735f41ae
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/accessible/linux/atspiadaptor.cpp | 118 | ||||
-rw-r--r-- | src/gui/accessible/linux/atspiadaptor_p.h | 4 |
2 files changed, 66 insertions, 56 deletions
diff --git a/src/gui/accessible/linux/atspiadaptor.cpp b/src/gui/accessible/linux/atspiadaptor.cpp index 0c27422364..4837b6e65f 100644 --- a/src/gui/accessible/linux/atspiadaptor.cpp +++ b/src/gui/accessible/linux/atspiadaptor.cpp @@ -28,6 +28,11 @@ It sends notifications coming from Qt via dbus and listens to incoming dbus requests. */ +// ATSPI_COORD_TYPE_PARENT was added in at-spi 2.30, define here for older versions +#if ATSPI_COORD_TYPE_COUNT < 3 +#define ATSPI_COORD_TYPE_PARENT 2 +#endif + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -1534,23 +1539,6 @@ static QAccessibleInterface * getWindow(QAccessibleInterface * interface) return parent; } -static QRect getRelativeRect(QAccessibleInterface *interface) -{ - QAccessibleInterface * window; - QRect wr, cr; - - cr = interface->rect(); - - window = getWindow(interface); - if (window) { - wr = window->rect(); - - cr.setX(cr.x() - wr.x()); - cr.setY(cr.y() - wr.y()); - } - return cr; -} - bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection) { if (function == "Contains"_L1) { @@ -1558,28 +1546,22 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt int x = message.arguments().at(0).toInt(); int y = message.arguments().at(1).toInt(); uint coordType = message.arguments().at(2).toUInt(); - if (coordType == ATSPI_COORD_TYPE_SCREEN) - ret = interface->rect().contains(x, y); - else - ret = getRelativeRect(interface).contains(x, y); + if (!isValidCoordType(coordType)) + return false; + ret = getExtents(interface, coordType).contains(x, y); sendReply(connection, message, ret); } else if (function == "GetAccessibleAtPoint"_L1) { - int x = message.arguments().at(0).toInt(); - int y = message.arguments().at(1).toInt(); + QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt()); uint coordType = message.arguments().at(2).toUInt(); - if (coordType == ATSPI_COORD_TYPE_WINDOW) { - QWindow * window = interface->window(); - if (window) { - x += window->position().x(); - y += window->position().y(); - } - } + if (!isValidCoordType(coordType)) + return false; + QPoint screenPos = translateToScreenCoordinates(interface, point, coordType); - QAccessibleInterface * childInterface(interface->childAt(x, y)); + QAccessibleInterface * childInterface(interface->childAt(screenPos.x(), screenPos.y())); QAccessibleInterface * iface = nullptr; while (childInterface) { iface = childInterface; - childInterface = iface->childAt(x, y); + childInterface = iface->childAt(screenPos.x(), screenPos.y()); } if (iface) { QString path = pathForInterface(iface); @@ -1593,6 +1575,8 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt sendReply(connection, message, (double) 1.0); } else if (function == "GetExtents"_L1) { uint coordType = message.arguments().at(0).toUInt(); + if (!isValidCoordType(coordType)) + return false; sendReply(connection, message, QVariant::fromValue(getExtents(interface, coordType))); } else if (function == "GetLayer"_L1) { sendReply(connection, message, QVariant::fromValue((uint)1)); @@ -1600,11 +1584,9 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt sendReply(connection, message, QVariant::fromValue((short)0)); } else if (function == "GetPosition"_L1) { uint coordType = message.arguments().at(0).toUInt(); - QRect rect; - if (coordType == ATSPI_COORD_TYPE_SCREEN) - rect = interface->rect(); - else - rect = getRelativeRect(interface); + if (!isValidCoordType(coordType)) + return false; + QRect rect = getExtents(interface, coordType); QVariantList pos; pos << rect.x() << rect.y(); connection.send(message.createReply(pos)); @@ -1649,7 +1631,7 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt QRect AtSpiAdaptor::getExtents(QAccessibleInterface *interface, uint coordType) { - return (coordType == ATSPI_COORD_TYPE_SCREEN) ? interface->rect() : getRelativeRect(interface); + return translateFromScreenCoordinates(interface, interface->rect(), coordType); } // Action interface @@ -1802,11 +1784,10 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString Q_ASSERT(!message.signature().isEmpty()); QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt()); uint coordType = message.arguments().at(2).toUInt(); - if (coordType == ATSPI_COORD_TYPE_WINDOW) { - QWindow *win = interface->window(); - point += QPoint(win->x(), win->y()); - } - int offset = interface->textInterface()->offsetAtPoint(point); + if (!isValidCoordType(coordType)) + return false; + QPoint screenPos = translateToScreenCoordinates(interface, point, coordType); + int offset = interface->textInterface()->offsetAtPoint(screenPos); sendReply(connection, message, offset); } else if (function == "GetRangeExtents"_L1) { int startOffset = message.arguments().at(0).toInt(); @@ -2053,10 +2034,7 @@ QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, in QList<QVariant> AtSpiAdaptor::getCharacterExtents(QAccessibleInterface *interface, int offset, uint coordType) const { QRect rect = interface->textInterface()->characterRect(offset); - - if (coordType == ATSPI_COORD_TYPE_WINDOW) - rect = translateRectToWindowCoordinates(interface, rect); - + rect = translateFromScreenCoordinates(interface, rect, coordType); return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height(); } @@ -2074,22 +2052,52 @@ QList<QVariant> AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface, for (int i=startOffset + 1; i <= endOffset; i++) rect = rect | textInterface->characterRect(i); - // relative to window - if (coordType == ATSPI_COORD_TYPE_WINDOW) - rect = translateRectToWindowCoordinates(interface, rect); - + rect = translateFromScreenCoordinates(interface, rect, coordType); return QList<QVariant>() << rect.x() << rect.y() << rect.width() << rect.height(); } -QRect AtSpiAdaptor::translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect) +bool AtSpiAdaptor::isValidCoordType(uint coordType) { - QAccessibleInterface * window = getWindow(interface); - if (window) - return rect.translated(-window->rect().x(), -window->rect().y()); + if (coordType == ATSPI_COORD_TYPE_SCREEN || coordType == ATSPI_COORD_TYPE_WINDOW || coordType == ATSPI_COORD_TYPE_PARENT) + return true; + + qCWarning(lcAccessibilityAtspi) << "unknown value" << coordType << "for AT-SPI coord type"; + return false; +} + +QRect AtSpiAdaptor::translateFromScreenCoordinates(QAccessibleInterface *interface, const QRect &screenRect, uint targetCoordType) +{ + Q_ASSERT(isValidCoordType(targetCoordType)); + + QAccessibleInterface *upper = nullptr; + if (targetCoordType == ATSPI_COORD_TYPE_WINDOW) + upper = getWindow(interface); + else if (targetCoordType == ATSPI_COORD_TYPE_PARENT) + upper = interface->parent(); + + QRect rect = screenRect; + if (upper) + rect.translate(-upper->rect().x(), -upper->rect().y()); return rect; } +QPoint AtSpiAdaptor::translateToScreenCoordinates(QAccessibleInterface *interface, const QPoint &pos, uint fromCoordType) +{ + Q_ASSERT(isValidCoordType(fromCoordType)); + + QAccessibleInterface *upper = nullptr; + if (fromCoordType == ATSPI_COORD_TYPE_WINDOW) + upper = getWindow(interface); + else if (fromCoordType == ATSPI_COORD_TYPE_PARENT) + upper = interface->parent(); + + QPoint screenPos = pos; + if (upper) + screenPos += upper->rect().topLeft(); + + return screenPos; +} // Editable Text interface static QString textForRange(QAccessibleInterface *accessible, int startOffset, int endOffset) diff --git a/src/gui/accessible/linux/atspiadaptor_p.h b/src/gui/accessible/linux/atspiadaptor_p.h index 3d785e4c25..a5fbf2e23d 100644 --- a/src/gui/accessible/linux/atspiadaptor_p.h +++ b/src/gui/accessible/linux/atspiadaptor_p.h @@ -94,7 +94,9 @@ private: // component helper functions static QRect getExtents(QAccessibleInterface *interface, uint coordType); - static QRect translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect); + static bool isValidCoordType(uint coordType); + static QRect translateFromScreenCoordinates(QAccessibleInterface *interface, const QRect &rect, uint targetCoordType); + static QPoint translateToScreenCoordinates(QAccessibleInterface *interface, const QPoint &pos, uint fromCoordType); // action helper functions QSpiActionArray getActions(QAccessibleInterface *interface) const; |