diff options
author | Morten Sørvig <[email protected]> | 2025-04-02 12:07:35 +0200 |
---|---|---|
committer | Morten Johan Sørvig <[email protected]> | 2025-05-01 02:44:18 +0000 |
commit | 51c7503568174669b48a8f8ddbe49eebb127a128 (patch) | |
tree | 50d0796b193267f88cda05a3c87b8aa547126357 | |
parent | e57fff63419867d59b6067fc1a5a3495678708dc (diff) |
a11y: reduce the number of activation observer calls
Reduce the number of activation calls by calling the
observer callbacks on active state change only, instead
of on each setActive() call.
The accessibility backends typically make setActive()
calls on each accessibility event, which can result
in a large number (100k+) of activation calls if there
are many (hundreds) of installed activation observers.
This change keeps the following behavior compatibilities:
- Each observer is called at least once on setActive(),
even if the active state has not changed since it was
installed.
- Going from active to inactive is supported, though
Qt currently does not appear to do this.
As a drive-by refactor, make it possible to activate
accessibility by calling QAccessible::setActive(), by
making it call QPlatformAccessible::setActive().
Change-Id: Iee17160f153b825be032b441923e3529c2f00242
Reviewed-by: Tor Arne Vestbø <[email protected]>
-rw-r--r-- | src/gui/accessible/qaccessible.cpp | 21 | ||||
-rw-r--r-- | src/gui/accessible/qplatformaccessibility.cpp | 18 | ||||
-rw-r--r-- | src/gui/accessible/qplatformaccessibility.h | 6 |
3 files changed, 39 insertions, 6 deletions
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index 510931b4760..87b29d8662c 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -688,6 +688,11 @@ void QAccessible::installActivationObserver(QAccessible::ActivationObserver *obs if (qAccessibleActivationObservers()->contains(observer)) return; qAccessibleActivationObservers()->append(observer); + + // Make sure the newly added observer gets a callback on the next + // QPlatformAccessibility::setActive() callback + if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) + pfAccessibility->clearActiveNotificationState(); } /*! @@ -702,6 +707,17 @@ void QAccessible::removeActivationObserver(ActivationObserver *observer) } /*! + \internal + + Sends accessibility activation notifications to all registered observers. +*/ +void qAccessibleNotifyActivationObservers(bool active) +{ + for (int i = 0; i < qAccessibleActivationObservers()->size(); ++i) + qAccessibleActivationObservers()->at(i)->accessibilityActiveChanged(active); +} + +/*! If a QAccessibleInterface implementation exists for the given \a object, this function returns a pointer to the implementation; otherwise it returns \nullptr. @@ -870,11 +886,10 @@ bool QAccessible::isActive() */ void QAccessible::setActive(bool active) { - for (int i = 0; i < qAccessibleActivationObservers()->size() ;++i) - qAccessibleActivationObservers()->at(i)->accessibilityActiveChanged(active); + if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) + pfAccessibility->setActive(active); } - /*! Sets the root object of the accessible objects of this application to \a object. All other accessible objects are reachable using object diff --git a/src/gui/accessible/qplatformaccessibility.cpp b/src/gui/accessible/qplatformaccessibility.cpp index ae7635ff7c9..4dd32a911c7 100644 --- a/src/gui/accessible/qplatformaccessibility.cpp +++ b/src/gui/accessible/qplatformaccessibility.cpp @@ -35,7 +35,6 @@ Q_GLOBAL_STATIC(QList<QAccessibleBridge *>, bridges) \sa QAccessible */ QPlatformAccessibility::QPlatformAccessibility() - : m_active(false) { } @@ -99,10 +98,25 @@ void QPlatformAccessibility::cleanup() qDeleteAll(*bridges()); } +void qAccessibleNotifyActivationObservers(bool active); // qaccessible.cpp + void QPlatformAccessibility::setActive(bool active) { m_active = active; - QAccessible::setActive(active); + + // Send activeChanged notifications if the new active status differs from + // the notifed one. + if ((active && m_activeNotificationState != std::optional<bool>{true}) || + (!active && m_activeNotificationState != std::optional<bool>{false})) { + qAccessibleNotifyActivationObservers(active); + } + + m_activeNotificationState = active; +} + +void QPlatformAccessibility::clearActiveNotificationState() +{ + m_activeNotificationState = std::nullopt; } #endif // QT_CONFIG(accessibility) diff --git a/src/gui/accessible/qplatformaccessibility.h b/src/gui/accessible/qplatformaccessibility.h index 004fcfb40fc..d262c2f6585 100644 --- a/src/gui/accessible/qplatformaccessibility.h +++ b/src/gui/accessible/qplatformaccessibility.h @@ -19,6 +19,8 @@ #include <QtCore/qobject.h> #include <QtGui/qaccessible.h> +#include <optional> + QT_BEGIN_NAMESPACE @@ -35,9 +37,11 @@ public: inline bool isActive() const { return m_active; } void setActive(bool active); + void clearActiveNotificationState(); private: - bool m_active; + bool m_active = false; + std::optional<bool> m_activeNotificationState = std::nullopt; }; QT_END_NAMESPACE |