diff options
Diffstat (limited to 'src/gui/accessible/linux/atspiadaptor.cpp')
-rw-r--r-- | src/gui/accessible/linux/atspiadaptor.cpp | 341 |
1 files changed, 271 insertions, 70 deletions
diff --git a/src/gui/accessible/linux/atspiadaptor.cpp b/src/gui/accessible/linux/atspiadaptor.cpp index 2e6fb720c5..b3269a2a95 100644 --- a/src/gui/accessible/linux/atspiadaptor.cpp +++ b/src/gui/accessible/linux/atspiadaptor.cpp @@ -11,11 +11,12 @@ #include <qclipboard.h> #include <QtCore/qloggingcategory.h> -#include <QtCore/qlibraryinfo.h> +#include <QtCore/qtversion.h> #if QT_CONFIG(accessibility) #include "socket_interface.h" #include "qspi_constant_mappings_p.h" +#include <QtCore/private/qstringiterator_p.h> #include <QtGui/private/qaccessiblebridgeutils_p.h> #include "qspiapplicationadaptor_p.h" @@ -167,6 +168,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const " <arg direction=\"out\" type=\"(so)\"/>\n" " <annotation value=\"QSpiObjectReference\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n" " </method>\n" + " <method name=\"GetAccessibleId\">\n" + " <arg direction=\"out\" type=\"s\"/>\n" + " </method>\n" " </interface>\n" ); @@ -307,6 +311,39 @@ QString AtSpiAdaptor::introspect(const QString &path) const " </interface>\n" ); + static const QLatin1StringView selectionIntrospection( + " <interface name=\"org.a11y.atspi.Selection\">\n" + " <property name=\"NSelectedChildren\" type=\"i\" access=\"read\"/>\n" + " <method name=\"GetSelectedChild\">\n" + " <arg direction=\"in\" name=\"selectedChildIndex\" type=\"i\"/>\n" + " <arg direction=\"out\" type=\"(so)\"/>\n" + " <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QSpiObjectReference\"/>\n" + " </method>\n" + " <method name=\"SelectChild\">\n" + " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n" + " <arg direction=\"out\" type=\"b\"/>\n" + " </method>\n" + " <method name=\"DeselectSelectedChild\">\n" + " <arg direction=\"in\" name=\"selectedChildIndex\" type=\"i\"/>\n" + " <arg direction=\"out\" type=\"b\"/>\n" + " </method>\n" + " <method name=\"IsChildSelected\">\n" + " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n" + " <arg direction=\"out\" type=\"b\"/>\n" + " </method>\n" + " <method name=\"SelectAll\">\n" + " <arg direction=\"out\" type=\"b\"/>\n" + " </method>\n" + " <method name=\"ClearSelection\">\n" + " <arg direction=\"out\" type=\"b\"/>\n" + " </method>\n" + " <method name=\"DeselectChild\">\n" + " <arg direction=\"in\" name=\"childIndex\" type=\"i\"/>\n" + " <arg direction=\"out\" type=\"b\"/>\n" + " </method>\n" + " </interface>\n" + ); + static const QLatin1StringView tableIntrospection( " <interface name=\"org.a11y.atspi.Table\">\n" " <property access=\"read\" type=\"i\" name=\"NRows\"/>\n" @@ -432,6 +469,14 @@ QString AtSpiAdaptor::introspect(const QString &path) const " <arg direction=\"out\" name=\"row_extents\" type=\"i\" />\n" " <arg direction=\"out\" name=\"col_extents\" type=\"i\" />\n" " </method>\n" + " <method name=\"GetColumnHeaderCells\">\n" + " <arg direction=\"out\" type=\"a(so)\"/>\n" + " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n" + " </method>\n" + " <method name=\"GetRowHeaderCells\">\n" + " <arg direction=\"out\" type=\"a(so)\"/>\n" + " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n" + " </method>\n" " </interface>\n" ); @@ -588,7 +633,7 @@ QString AtSpiAdaptor::introspect(const QString &path) const QAccessibleInterface * interface = interfaceFromPath(path); if (!interface) { - qCDebug(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Could not find accessible on path: " << path; + qCWarning(lcAccessibilityAtspi) << "Could not find accessible on path:" << path; return QString(); } @@ -605,6 +650,8 @@ QString AtSpiAdaptor::introspect(const QString &path) const xml.append(editableTextIntrospection); if (interfaces.contains(ATSPI_DBUS_INTERFACE_ACTION ""_L1)) xml.append(actionIntrospection); + if (interfaces.contains(ATSPI_DBUS_INTERFACE_SELECTION ""_L1)) + xml.append(selectionIntrospection); if (interfaces.contains(ATSPI_DBUS_INTERFACE_TABLE ""_L1)) xml.append(tableIntrospection); if (interfaces.contains(ATSPI_DBUS_INTERFACE_TABLE_CELL ""_L1)) @@ -699,7 +746,7 @@ void AtSpiAdaptor::setBitFlag(const QString &flag) || right.startsWith("VisibledataChanged"_L1)) { // typo in libatspi sendObject_visible_data_changed = 1; } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: subscription string not handled:" << flag; + qCWarning(lcAccessibilityAtspi) << "Subscription string not handled:" << flag; } } break; @@ -745,7 +792,7 @@ void AtSpiAdaptor::setBitFlag(const QString &flag) } else if (right.startsWith("DesktopDestroy"_L1)) { // ignore this one } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: subscription string not handled:" << flag; + qCWarning(lcAccessibilityAtspi) << "Subscription string not handled:" << flag; } } break; @@ -764,7 +811,7 @@ void AtSpiAdaptor::setBitFlag(const QString &flag) break; } default: - qCDebug(lcAccessibilityAtspi) << "WARNING: subscription string not handled:" << flag; + qCWarning(lcAccessibilityAtspi) << "Subscription string not handled:" << flag; } } @@ -917,8 +964,17 @@ void AtSpiAdaptor::notify(QAccessibleEvent *event) } case QAccessible::NameChanged: { if (sendObject || sendObject_property_change || sendObject_property_change_accessible_name) { - QString path = pathForInterface(event->accessibleInterface()); - QVariantList args = packDBusSignalArguments("accessible-name"_L1, 0, 0, variantForPath(path)); + QAccessibleInterface *iface = event->accessibleInterface(); + if (!iface) { + qCDebug(lcAccessibilityAtspi, + "NameChanged event from invalid accessible."); + return; + } + + QString path = pathForInterface(iface); + QVariantList args = packDBusSignalArguments( + "accessible-name"_L1, 0, 0, + QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Name)))); sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "PropertyChange"_L1, args); } @@ -926,8 +982,17 @@ void AtSpiAdaptor::notify(QAccessibleEvent *event) } case QAccessible::DescriptionChanged: { if (sendObject || sendObject_property_change || sendObject_property_change_accessible_description) { - QString path = pathForInterface(event->accessibleInterface()); - QVariantList args = packDBusSignalArguments("accessible-description"_L1, 0, 0, variantForPath(path)); + QAccessibleInterface *iface = event->accessibleInterface(); + if (!iface) { + qCDebug(lcAccessibilityAtspi, + "DescriptionChanged event from invalid accessible."); + return; + } + + QString path = pathForInterface(iface); + QVariantList args = packDBusSignalArguments( + "accessible-description"_L1, 0, 0, + QVariant::fromValue(QDBusVariant(iface->text(QAccessible::Description)))); sendDBusSignal(path, ATSPI_DBUS_INTERFACE_EVENT_OBJECT ""_L1, "PropertyChange"_L1, args); } @@ -944,7 +1009,7 @@ void AtSpiAdaptor::notify(QAccessibleEvent *event) if (sendObject || sendObject_text_changed) { QAccessibleInterface * iface = event->accessibleInterface(); if (!iface || !iface->textInterface()) { - qCDebug(lcAccessibilityAtspi) << "Received text event for invalid interface."; + qCWarning(lcAccessibilityAtspi) << "Received text event for invalid interface."; return; } QString path = pathForInterface(iface); @@ -1337,11 +1402,11 @@ bool AtSpiAdaptor::handleMessage(const QDBusMessage &message, const QDBusConnect // get accessible interface QAccessibleInterface * accessible = interfaceFromPath(message.path()); if (!accessible) { - qCDebug(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Could not find accessible on path: " << message.path(); + qCWarning(lcAccessibilityAtspi) << "Could not find accessible on path:" << message.path(); return false; } if (!accessible->isValid()) { - qCWarning(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Accessible invalid: " << accessible << message.path(); + qCWarning(lcAccessibilityAtspi) << "Accessible invalid:" << accessible << message.path(); return false; } @@ -1371,6 +1436,8 @@ bool AtSpiAdaptor::handleMessage(const QDBusMessage &message, const QDBusConnect return componentInterface(accessible, function, message, connection); if (interface == ATSPI_DBUS_INTERFACE_ACTION ""_L1) return actionInterface(accessible, function, message, connection); + if (interface == ATSPI_DBUS_INTERFACE_SELECTION ""_L1) + return selectionInterface(accessible, function, message, connection); if (interface == ATSPI_DBUS_INTERFACE_TEXT ""_L1) return textInterface(accessible, function, message, connection); if (interface == ATSPI_DBUS_INTERFACE_EDITABLE_TEXT ""_L1) @@ -1390,7 +1457,7 @@ bool AtSpiAdaptor::handleMessage(const QDBusMessage &message, const QDBusConnect bool AtSpiAdaptor::applicationInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection) { if (message.path() != ATSPI_DBUS_PATH_ROOT ""_L1) { - qCDebug(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Could not find application interface for: " << message.path() << interface; + qCWarning(lcAccessibilityAtspi) << "Could not find application interface for:" << message.path() << interface; return false; } @@ -1442,13 +1509,33 @@ void AtSpiAdaptor::registerApplication() const QSpiObjectReference &socket = reply.value(); accessibilityRegistry = QSpiObjectReference(socket); } else { - qCDebug(lcAccessibilityAtspi) << "Error in contacting registry: " + qCWarning(lcAccessibilityAtspi) << "Error in contacting registry:" << reply.error().name() << reply.error().message(); } delete registry; } +namespace { +QString accessibleIdForAccessible(QAccessibleInterface *accessible) +{ + QString result; + while (accessible) { + if (!result.isEmpty()) + result.prepend(u'.'); + if (auto obj = accessible->object()) { + const QString name = obj->objectName(); + if (!name.isEmpty()) + result.prepend(name); + else + result.prepend(QString::fromUtf8(obj->metaObject()->className())); + } + accessible = accessible->parent(); + } + return result; +} +} // namespace + // Accessible bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection) { @@ -1535,8 +1622,11 @@ bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QS children << ref; } connection.send(message.createReply(QVariant::fromValue(children))); + } else if (function == "GetAccessibleId"_L1) { + sendReply(connection, message, + QVariant::fromValue(QDBusVariant(accessibleIdForAccessible(interface)))); } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::accessibleInterface does not implement " << function << message.path(); + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::accessibleInterface does not implement" << function << message.path(); return false; } return true; @@ -1573,6 +1663,9 @@ QStringList AtSpiAdaptor::accessibleInterfaces(QAccessibleInterface *interface) if (interface->actionInterface() || interface->valueInterface()) ifaces << u"" ATSPI_DBUS_INTERFACE_ACTION ""_s; + if (interface->selectionInterface()) + ifaces << ATSPI_DBUS_INTERFACE_SELECTION ""_L1; + if (interface->textInterface()) ifaces << u"" ATSPI_DBUS_INTERFACE_TEXT ""_s; @@ -1623,7 +1716,7 @@ QString AtSpiAdaptor::pathForObject(QObject *object) const Q_ASSERT(object); if (inheritsQAction(object)) { - qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::pathForObject: warning: creating path with QAction as object."; + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::pathForObject: Creating path with QAction as object."; } QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(object); @@ -1657,15 +1750,14 @@ bool AtSpiAdaptor::inheritsQAction(QObject *object) // Component static QAccessibleInterface * getWindow(QAccessibleInterface * interface) { - if (interface->role() == QAccessible::Dialog || interface->role() == QAccessible::Window) - return interface; - - QAccessibleInterface * parent = interface->parent(); - while (parent && parent->role() != QAccessible::Dialog - && parent->role() != QAccessible::Window) - parent = parent->parent(); - - return parent; + // 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; } bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection) @@ -1752,7 +1844,7 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt qCDebug(lcAccessibilityAtspi) << "SetSize is not implemented."; sendReply(connection, message, false); } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::componentInterface does not implement " << function << message.path(); + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::componentInterface does not implement" << function << message.path(); return false; } return true; @@ -1767,12 +1859,12 @@ QRect AtSpiAdaptor::getExtents(QAccessibleInterface *interface, uint coordType) bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection) { if (function == "GetNActions"_L1) { - int count = QAccessibleBridgeUtils::effectiveActionNames(interface).count(); + int count = QAccessibleBridgeUtils::effectiveActionNames(interface).size(); sendReply(connection, message, QVariant::fromValue(QDBusVariant(QVariant::fromValue(count)))); } else if (function == "DoAction"_L1) { int index = message.arguments().at(0).toInt(); const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface); - if (index < 0 || index >= actionNames.count()) + if (index < 0 || index >= actionNames.size()) return false; const QString actionName = actionNames.at(index); bool success = QAccessibleBridgeUtils::performEffectiveAction(interface, actionName); @@ -1782,13 +1874,13 @@ bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, const QStrin } else if (function == "GetName"_L1) { int index = message.arguments().at(0).toInt(); const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface); - if (index < 0 || index >= actionNames.count()) + if (index < 0 || index >= actionNames.size()) return false; sendReply(connection, message, actionNames.at(index)); } else if (function == "GetDescription"_L1) { int index = message.arguments().at(0).toInt(); const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface); - if (index < 0 || index >= actionNames.count()) + if (index < 0 || index >= actionNames.size()) return false; QString description; if (QAccessibleActionInterface *actionIface = interface->actionInterface()) @@ -1799,7 +1891,7 @@ bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, const QStrin } else if (function == "GetKeyBinding"_L1) { int index = message.arguments().at(0).toInt(); const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(interface); - if (index < 0 || index >= actionNames.count()) + if (index < 0 || index >= actionNames.size()) return false; QStringList keyBindings; if (QAccessibleActionInterface *actionIface = interface->actionInterface()) @@ -1809,12 +1901,12 @@ bool AtSpiAdaptor::actionInterface(QAccessibleInterface *interface, const QStrin if (!acc.isEmpty()) keyBindings.append(acc); } - if (keyBindings.length() > 0) + if (keyBindings.size() > 0) sendReply(connection, message, keyBindings.join(u';')); else sendReply(connection, message, QString()); } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::actionInterface does not implement " << function << message.path(); + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::actionInterface does not implement" << function << message.path(); return false; } return true; @@ -1896,8 +1988,13 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString int offset = message.arguments().at(0).toInt(); int start; int end; - QString result = interface->textInterface()->textAtOffset(offset, QAccessible::CharBoundary, &start, &end); - sendReply(connection, message, (int) *(qPrintable (result))); + const QString charString = interface->textInterface() + ->textAtOffset(offset, QAccessible::CharBoundary, &start, &end); + int codePoint = 0; + QStringIterator stringIt(charString); + if (stringIt.hasNext()) + codePoint = static_cast<int>(stringIt.peekNext()); + sendReply(connection, message, codePoint); } else if (function == "GetCharacterExtents"_L1) { int offset = message.arguments().at(0).toInt(); int coordType = message.arguments().at(1).toUInt(); @@ -1994,7 +2091,7 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString interface->textInterface()->setSelection(selectionNum, startOffset, endOffset); sendReply(connection, message, true); } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::textInterface does not implement " << function << message.path(); + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::textInterface does not implement" << function << message.path(); return false; } return true; @@ -2063,7 +2160,7 @@ namespace QString atspiColor(const QString &ia2Color) { // "rgb(%u,%u,%u)" -> "%u,%u,%u" - return ia2Color.mid(4, ia2Color.size() - (4+1)); + return ia2Color.mid(4, ia2Color.size() - (4+1)).replace(u"\\,"_s, u","_s); } QString atspiSize(const QString &ia2Size) @@ -2077,9 +2174,9 @@ namespace QString name = ia2Name; QString value = ia2Value; - // IAccessible2: http://www.linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2/textattributes - // ATK attribute names: https://git.gnome.org/browse/orca/tree/src/orca/text_attribute_names.py - // ATK attribute values: https://developer.gnome.org/atk/unstable/AtkText.html#AtkTextAttribute + // IAccessible2: https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes + // ATK attribute names: https://gitlab.gnome.org/GNOME/orca/-/blob/master/src/orca/text_attribute_names.py + // ATK attribute values: https://gnome.pages.gitlab.gnome.org/atk/AtkText.html#AtkTextAttribute // https://bugzilla.gnome.org/show_bug.cgi?id=744553 "ATK docs provide no guidance for allowed values of some text attributes" // specifically for "weight", "invalid", "language" and value range for colors @@ -2125,6 +2222,13 @@ namespace // (on which it produces traceback and fails to read any following text attributes), // but that is the default value, so omit it anyway value = QString(); + } else if (((ia2Name == "text-line-through-style"_L1 || ia2Name == "text-line-through-type"_L1) && (ia2Value != "none"_L1)) + || (ia2Name == "text-line-through-text"_L1 && !ia2Value.isEmpty())) { + // if any of the above is set, set "strikethrough" to true, but don't explicitly set + // to false otherwise, since any of the others might still be set to indicate strikethrough + // and no strikethrough is assumed anyway when nothing is explicitly set + name = QStringLiteral("strikethrough"); + value = QStringLiteral("true"); } else if (ia2Name == "text-position"_L1) { name = QStringLiteral("vertical-align"); if (value != "baseline"_L1 && value != "super"_L1 && value != "sub"_L1) { @@ -2172,11 +2276,13 @@ QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int of QString joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset); const QStringList attributes = joined.split(u';', Qt::SkipEmptyParts, Qt::CaseSensitive); for (const QString &attr : attributes) { - QStringList items; - items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive); - AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]); - if (!attribute.isNull()) - set[attribute.name] = attribute.value; + QStringList items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive); + if (items.count() == 2) + { + AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]); + if (!attribute.isNull()) + set[attribute.name] = attribute.value; + } } QVariantList list; @@ -2234,7 +2340,7 @@ bool AtSpiAdaptor::isValidCoordType(uint coordType) 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"; + qCWarning(lcAccessibilityAtspi) << "Unknown value" << coordType << "for AT-SPI coord type"; return false; } @@ -2358,7 +2464,7 @@ bool AtSpiAdaptor::editableTextInterface(QAccessibleInterface *interface, const } else if (function.isEmpty()) { connection.send(message.createReply()); } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::editableTextInterface does not implement " << function << message.path(); + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::editableTextInterface does not implement" << function << message.path(); return false; } return true; @@ -2389,11 +2495,11 @@ bool AtSpiAdaptor::valueInterface(QAccessibleInterface *interface, const QString else if (function == "GetMinimumValue"_L1) value = valueIface->minimumValue(); else { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::valueInterface does not implement " << function << message.path(); + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::valueInterface does not implement" << function << message.path(); return false; } if (!value.canConvert<double>()) { - qCDebug(lcAccessibilityAtspi) << "AtSpiAdaptor::valueInterface: Could not convert to double: " << function; + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::valueInterface: Could not convert to double:" << function; } // explicitly convert to dbus-variant containing one double since atspi expects that @@ -2404,11 +2510,68 @@ bool AtSpiAdaptor::valueInterface(QAccessibleInterface *interface, const QString return true; } +// Selection interface +bool AtSpiAdaptor::selectionInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection) +{ + QAccessibleSelectionInterface* selectionInterface = interface->selectionInterface(); + if (!selectionInterface) { + qCWarning(lcAccessibilityAtspi) << "Could not find selection interface for: " << message.path() << interface; + return false; + } + + if (function == "ClearSelection"_L1 ) { + connection.send(message.createReply(QVariant::fromValue((selectionInterface->clear())))); + } else if (function == "DeselectChild"_L1 ) { + int childIndex = message.arguments().at(0).toInt(); + bool ret = false; + QAccessibleInterface *child = interface->child(childIndex); + if (child) + ret = selectionInterface->unselect(child); + connection.send(message.createReply(QVariant::fromValue(ret))); + } else if (function == "DeselectSelectedChild"_L1 ) { + int selectionIndex = message.arguments().at(0).toInt(); + bool ret = false; + QAccessibleInterface *selectedChild = selectionInterface->selectedItem(selectionIndex); + if (selectedChild) + ret = selectionInterface->unselect(selectedChild); + connection.send(message.createReply(QVariant::fromValue(ret))); + } else if (function == "GetNSelectedChildren"_L1) { + connection.send(message.createReply(QVariant::fromValue(QDBusVariant( + QVariant::fromValue(selectionInterface->selectedItemCount()))))); + } else if (function == "GetSelectedChild"_L1) { + int selectionIndex = message.arguments().at(0).toInt(); + QSpiObjectReference ref(connection, QDBusObjectPath(pathForInterface(selectionInterface->selectedItem(selectionIndex)))); + connection.send(message.createReply(QVariant::fromValue(ref))); + } else if (function == "IsChildSelected"_L1 ) { + int childIndex = message.arguments().at(0).toInt(); + bool ret = false; + QAccessibleInterface *child = interface->child(childIndex); + if (child) + ret = selectionInterface->isSelected(child); + connection.send(message.createReply(QVariant::fromValue(ret))); + } else if (function == "SelectAll"_L1 ) { + connection.send(message.createReply(QVariant::fromValue(selectionInterface->selectAll()))); + } else if (function == "SelectChild"_L1 ) { + int childIndex = message.arguments().at(0).toInt(); + bool ret = false; + QAccessibleInterface *child = interface->child(childIndex); + if (child) + ret = selectionInterface->select(child); + connection.send(message.createReply(QVariant::fromValue(ret))); + } else { + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::selectionInterface does not implement " << function << message.path(); + return false; + } + + return true; +} + + // Table interface bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection) { if (!(interface->tableInterface() || interface->tableCellInterface())) { - qCDebug(lcAccessibilityAtspi) << "WARNING Qt AtSpiAdaptor: Could not find table interface for: " << message.path() << interface; + qCWarning(lcAccessibilityAtspi) << "Qt AtSpiAdaptor: Could not find table interface for:" << message.path() << interface; return false; } @@ -2444,7 +2607,7 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString (column < 0) || (row >= interface->tableInterface()->rowCount()) || (column >= interface->tableInterface()->columnCount())) { - qCDebug(lcAccessibilityAtspi) << "WARNING: invalid index for tableInterface GetAccessibleAt (" << row << ", " << column << ')'; + qCWarning(lcAccessibilityAtspi) << "Invalid index for tableInterface GetAccessibleAt (" << row << "," << column << ')'; return false; } @@ -2453,7 +2616,7 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString if (cell) { ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(cell))); } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: no cell interface returned for " << interface->object() << row << column; + qCWarning(lcAccessibilityAtspi) << "No cell interface returned for" << interface->object() << row << column; ref = QSpiObjectReference(); } connection.send(message.createReply(QVariant::fromValue(ref))); @@ -2463,7 +2626,7 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString int column = message.arguments().at(1).toInt(); QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column); if (!cell) { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::GetIndexAt(" << row << ',' << column << ") did not find a cell. " << interface; + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::GetIndexAt(" << row << ',' << column << ") did not find a cell." << interface; return false; } int index = interface->indexOfChild(cell); @@ -2483,7 +2646,7 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString ret = -1; } else { if (!cell->tableCellInterface()) { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::" << function << " No table cell interface: " << cell; + qCWarning(lcAccessibilityAtspi).nospace() << "AtSpiAdaptor::" << function << " No table cell interface: " << cell; return false; } ret = cell->tableCellInterface()->columnIndex(); @@ -2495,14 +2658,14 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString ret = index % interface->tableInterface()->columnCount(); } else { if (!cell->tableCellInterface()) { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::" << function << " No table cell interface: " << cell; + qCWarning(lcAccessibilityAtspi).nospace() << "AtSpiAdaptor::" << function << " No table cell interface: " << cell; return false; } ret = cell->tableCellInterface()->rowIndex(); } } } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::" << function << " No cell at index: " << index << interface; + qCWarning(lcAccessibilityAtspi).nospace() << "AtSpiAdaptor::" << function << " No cell at index: " << index << " " << interface; return false; } } @@ -2531,14 +2694,15 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString if (cols > 0) { row = index / cols; col = index % cols; - QAccessibleTableCellInterface *cell = interface->tableInterface()->cellAt(row, col)->tableCellInterface(); - if (cell) { - row = cell->rowIndex(); - col = cell->columnIndex(); - rowExtents = cell->rowExtent(); - colExtents = cell->columnExtent(); - isSelected = cell->isSelected(); - success = true; + if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, col)) { + if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface()) { + row = cellIface->rowIndex(); + col = cellIface->columnIndex(); + rowExtents = cellIface->rowExtent(); + colExtents = cellIface->columnExtent(); + isSelected = cellIface->isSelected(); + success = true; + } } } QVariantList list; @@ -2548,12 +2712,22 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString } else if (function == "GetColumnExtentAt"_L1) { int row = message.arguments().at(0).toInt(); int column = message.arguments().at(1).toInt(); - connection.send(message.createReply(interface->tableInterface()->cellAt(row, column)->tableCellInterface()->columnExtent())); + int columnExtent = 0; + if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column)) { + if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface()) + columnExtent = cellIface->columnExtent(); + } + connection.send(message.createReply(columnExtent)); } else if (function == "GetRowExtentAt"_L1) { int row = message.arguments().at(0).toInt(); int column = message.arguments().at(1).toInt(); - connection.send(message.createReply(interface->tableInterface()->cellAt(row, column)->tableCellInterface()->rowExtent())); + int rowExtent = 0; + if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column)) { + if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface()) + rowExtent = cellIface->rowExtent(); + } + connection.send(message.createReply(rowExtent)); } else if (function == "GetColumnHeader"_L1) { int column = message.arguments().at(0).toInt(); @@ -2593,8 +2767,12 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString } else if (function == "IsSelected"_L1) { int row = message.arguments().at(0).toInt(); int column = message.arguments().at(1).toInt(); - QAccessibleTableCellInterface* cell = interface->tableInterface()->cellAt(row, column)->tableCellInterface(); - connection.send(message.createReply(cell->isSelected())); + bool selected = false; + if (QAccessibleInterface* cell = interface->tableInterface()->cellAt(row, column)) { + if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface()) + selected = cellIface->isSelected(); + } + connection.send(message.createReply(selected)); } else if (function == "AddColumnSelection"_L1) { int column = message.arguments().at(0).toInt(); connection.send(message.createReply(interface->tableInterface()->selectColumn(column))); @@ -2608,7 +2786,7 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString int row = message.arguments().at(0).toInt(); connection.send(message.createReply(interface->tableInterface()->unselectRow(row))); } else { - qCDebug(lcAccessibilityAtspi) << "WARNING: AtSpiAdaptor::tableInterface does not implement " << function << message.path(); + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::tableInterface does not implement" << function << message.path(); return false; } return true; @@ -2623,7 +2801,17 @@ bool AtSpiAdaptor::tableCellInterface(QAccessibleInterface *interface, const QSt return false; } - if (function == "GetColumnSpan"_L1) { + if (function == "GetColumnHeaderCells"_L1) { + QSpiObjectReferenceArray headerCells; + const auto headerCellInterfaces = cellInterface->columnHeaderCells(); + headerCells.reserve(headerCellInterfaces.size()); + for (QAccessibleInterface *cell : headerCellInterfaces) { + const QString childPath = pathForInterface(cell); + const QSpiObjectReference ref(connection, QDBusObjectPath(childPath)); + headerCells << ref; + } + connection.send(message.createReply(QVariant::fromValue(headerCells))); + } else if (function == "GetColumnSpan"_L1) { connection.send(message.createReply(QVariant::fromValue(QDBusVariant( QVariant::fromValue(cellInterface->columnExtent()))))); } else if (function == "GetPosition"_L1) { @@ -2631,6 +2819,16 @@ bool AtSpiAdaptor::tableCellInterface(QAccessibleInterface *interface, const QSt const int column = cellInterface->columnIndex(); connection.send(message.createReply(QVariant::fromValue(QDBusVariant( QVariant::fromValue(QPoint(row, column)))))); + } else if (function == "GetRowHeaderCells"_L1) { + QSpiObjectReferenceArray headerCells; + const auto headerCellInterfaces = cellInterface->rowHeaderCells(); + headerCells.reserve(headerCellInterfaces.size()); + for (QAccessibleInterface *cell : headerCellInterfaces) { + const QString childPath = pathForInterface(cell); + const QSpiObjectReference ref(connection, QDBusObjectPath(childPath)); + headerCells << ref; + } + connection.send(message.createReply(QVariant::fromValue(headerCells))); } else if (function == "GetRowSpan"_L1) { connection.send(message.createReply(QVariant::fromValue(QDBusVariant( QVariant::fromValue(cellInterface->rowExtent()))))); @@ -2644,6 +2842,9 @@ bool AtSpiAdaptor::tableCellInterface(QAccessibleInterface *interface, const QSt if (table && table->tableInterface()) ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(table))); connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref))))); + } else { + qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::tableCellInterface does not implement" << function << message.path(); + return false; } return true; |