summaryrefslogtreecommitdiffstats
path: root/src/gui/accessible
diff options
context:
space:
mode:
authorMichael Weghorn <m.weghorn@posteo.de>2022-08-03 07:42:10 +0200
committerMichael Weghorn <m.weghorn@posteo.de>2022-08-17 10:48:59 +0200
commita32a3aa388534f67da02fd7f15a59648637bd753 (patch)
tree5e631d3b4f5ba9001f6396ab67c4f05dc949de17 /src/gui/accessible
parent4d6decf628af9b19ed6381cc2fa9b91823c47bca (diff)
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/gui/accessible')
-rw-r--r--src/gui/accessible/linux/atspiadaptor.cpp118
-rw-r--r--src/gui/accessible/linux/atspiadaptor_p.h4
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;