summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorten Sørvig <[email protected]>2025-04-02 12:07:35 +0200
committerMorten Johan Sørvig <[email protected]>2025-05-01 02:44:18 +0000
commit51c7503568174669b48a8f8ddbe49eebb127a128 (patch)
tree50d0796b193267f88cda05a3c87b8aa547126357
parente57fff63419867d59b6067fc1a5a3495678708dc (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.cpp21
-rw-r--r--src/gui/accessible/qplatformaccessibility.cpp18
-rw-r--r--src/gui/accessible/qplatformaccessibility.h6
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