a11y atspi: Watch for enabled status change

On log-in this may be disabled and only enabled later; that prevents
clients like plasmashell to enable a11y features.
We need to watch changes to the org.a11y.Status properties and enable
the a11y integration on-demand.

As the in-line comment said, qdbusxml2cpp does not generate NOTIFY
signals for DBus properties, so use the raw PropertiesChanged signal
to receive those notifications.

Downstream bugs:
- https://bugs.kde.org/show_bug.cgi?id=495096
- https://bugs.kde.org/show_bug.cgi?id=495098

Pick-to: 6.7
Pick-to: 6.7
Change-Id: I4d0adf61af875464d3cd47759631d2a3aac664f0
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
(cherry picked from commit 38251c36edf11316a2467169b1d491bf13520fd3)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Alessandro Astone 2024-10-20 20:49:26 +02:00 committed by Qt Cherry-pick Bot
parent 78dfb5f196
commit 50aaa93c85
4 changed files with 47 additions and 15 deletions

View File

@ -565,6 +565,7 @@ qt_internal_extend_target(Gui CONDITION atspi_accessibility
DBUS_INTERFACE_SOURCES
accessible/linux/dbusxml/Bus.xml
accessible/linux/dbusxml/Socket.xml
accessible/linux/dbusxml/org.freedesktop.DBus.Properties.xml
DBUS_INTERFACE_FLAGS
"-i" "QtGui/private/qspi_struct_marshallers_p.h"
)

View File

@ -10,7 +10,6 @@
#include <qdebug.h>
#include <QDBusConnectionInterface>
#include "bus_interface.h"
#include <QtGui/qguiapplication.h>
#include <qpa/qplatformnativeinterface.h>
@ -49,12 +48,22 @@ QAtSpiDBusConnection::QAtSpiDBusConnection(QObject *parent)
return;
}
m_a11yStatus = new OrgA11yStatusInterface(A11Y_SERVICE, A11Y_PATH, c, this);
m_dbusProperties = new OrgFreedesktopDBusPropertiesInterface(A11Y_SERVICE, A11Y_PATH, c, this);
dbusWatcher = new QDBusServiceWatcher(A11Y_SERVICE, c, QDBusServiceWatcher::WatchForRegistration, this);
connect(dbusWatcher, SIGNAL(serviceRegistered(QString)), this, SLOT(serviceRegistered()));
connect(dbusWatcher, SIGNAL(checkEnabledState(QString)), this, SLOT(checkEnabledState()));
// If it is registered already, setup a11y right away
if (c.interface()->isServiceRegistered(A11Y_SERVICE))
serviceRegistered();
checkEnabledState();
// Subscribe to updates about a11y enabled state.
connect(m_dbusProperties, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
this, [this](const QString &interface_name) {
if (interface_name == QLatin1StringView(OrgA11yStatusInterface::staticInterfaceName()))
checkEnabledState();
});
if (QGuiApplication::platformName().startsWith("xcb"_L1)) {
// In addition try if there is an xatom exposing the bus address, this allows applications run as root to work
@ -82,21 +91,14 @@ QString QAtSpiDBusConnection::getAddressFromXCB()
return QString();
}
// We have the a11y registry on the session bus.
// Subscribe to updates about a11y enabled state.
// Find out the bus address
void QAtSpiDBusConnection::serviceRegistered()
void QAtSpiDBusConnection::checkEnabledState()
{
// listen to enabled changes
QDBusConnection c = QDBusConnection::sessionBus();
OrgA11yStatusInterface *a11yStatus = new OrgA11yStatusInterface(A11Y_SERVICE, A11Y_PATH, c, this);
//The variable was introduced because on some embedded platforms there are custom accessibility
//clients which don't set Status.ScreenReaderEnabled to true. The variable is also useful for
//debugging.
static const bool a11yAlwaysOn = qEnvironmentVariableIsSet("QT_LINUX_ACCESSIBILITY_ALWAYS_ON");
bool enabled = a11yAlwaysOn || a11yStatus->screenReaderEnabled() || a11yStatus->isEnabled();
bool enabled = a11yAlwaysOn || m_a11yStatus->screenReaderEnabled() || m_a11yStatus->isEnabled();
if (enabled != m_enabled) {
m_enabled = enabled;
@ -109,8 +111,6 @@ void QAtSpiDBusConnection::serviceRegistered()
c.callWithCallback(m, this, SLOT(connectA11yBus(QString)), SLOT(dbusError(QDBusError)));
}
}
// connect(a11yStatus, ); QtDbus doesn't support notifications for property changes yet
}
void QAtSpiDBusConnection::serviceUnregistered()

View File

@ -23,6 +23,9 @@
#include <QtCore/private/qglobal_p.h>
Q_MOC_INCLUDE(<QtDBus/QDBusError>)
#include "bus_interface.h"
#include "properties_interface.h"
QT_BEGIN_NAMESPACE
class QDBusServiceWatcher;
@ -42,7 +45,7 @@ Q_SIGNALS:
private Q_SLOTS:
QString getAddressFromXCB();
void serviceRegistered();
void checkEnabledState();
void serviceUnregistered();
void connectA11yBus(const QString &address);
@ -52,6 +55,8 @@ private:
QString getAccessibilityBusAddress() const;
QDBusServiceWatcher *dbusWatcher;
OrgFreedesktopDBusPropertiesInterface *m_dbusProperties;
OrgA11yStatusInterface *m_a11yStatus;
QDBusConnection m_a11yConnection;
bool m_enabled;
};

View File

@ -0,0 +1,26 @@
<?xml version="1.0" ?>
<node>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="out"/>
</method>
<method name="GetAll">
<arg type="s" name="interface_name" direction="in"/>
<arg type="a{sv}" name="properties" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
</method>
<method name="Set">
<arg type="s" name="interface_name" direction="in"/>
<arg type="s" name="property_name" direction="in"/>
<arg type="v" name="value" direction="in"/>
</method>
<signal name="PropertiesChanged">
<arg type="s" name="interface_name"/>
<arg type="a{sv}" name="changed_properties"/>
<arg type="as" name="invalidated_properties"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
</signal>
</interface>
</node>