File 2512ffea91bbaec41d55eea2813a365edc3160a5.patch of Package qt6-declarative
From 2512ffea91bbaec41d55eea2813a365edc3160a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= <jan-arve.saether@qt.io>
Date: Wed, 10 Sep 2025 20:19:40 +0200
Subject: [PATCH] a11y: Send missing QAccessible::ObjectShow event for Qt Quick
Controls
Before sending the QAccessibleEvent QAccessible::ObjectShow event from
QQuickItemPrivate::setEffectiveVisibleRecur() we checked if
QQuickItemPrivate::isAccessible was set. For e.g. Button, isAccessible
wasn't set by default: This was because isAccessible was only set as a
response to that an Accessible attached property was assigned to the
item.
Therefore, when a Button was shown it could end up not sending the
QAccessible::ObjectShow event.
This problem was first found on Button, but after more investigation, we
have found that the same problem applies to:
* BusyIndicator
* Button
* ComboBox
* Dial
* Label (without a text)
* ProgressBar
* RangeSlider
* RoundButton
* Slider
* TextArea
* TextField
The fix is to explicitly enable accessibility by calling
QQuickItemPrivate::setAccessible() on *all* Qt Quick Controls, since
they are all supposed to be accessible.
Change-Id: If4fa050149a31bf2baffa208716341d21631c042
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
---
src/quicktemplates/qquickcontrol.cpp | 3 ++
src/quicktemplates/qquicklabel.cpp | 1 +
src/quicktemplates/qquicktextarea.cpp | 3 ++
src/quicktemplates/qquicktextfield.cpp | 1 +
.../qquickaccessible/tst_qquickaccessible.cpp | 52 +++++++++++++++++++
5 files changed, 60 insertions(+)
diff --git a/src/quicktemplates/qquickcontrol.cpp b/src/quicktemplates/qquickcontrol.cpp
index 2585078a76f..0c524aac218 100644
--- a/src/quicktemplates/qquickcontrol.cpp
+++ b/src/quicktemplates/qquickcontrol.cpp
@@ -138,6 +138,9 @@ void QQuickControlPrivate::init()
{
Q_Q(QQuickControl);
QObject::connect(q, &QQuickItem::baselineOffsetChanged, q, &QQuickControl::baselineOffsetChanged);
+#if QT_CONFIG(accessibility)
+ setAccessible();
+#endif
}
#if QT_CONFIG(quicktemplates2_multitouch)
diff --git a/src/quicktemplates/qquicklabel.cpp b/src/quicktemplates/qquicklabel.cpp
index 793cab71657..70142321d5d 100644
--- a/src/quicktemplates/qquicklabel.cpp
+++ b/src/quicktemplates/qquicklabel.cpp
@@ -51,6 +51,7 @@ QQuickLabelPrivate::QQuickLabelPrivate()
{
#if QT_CONFIG(accessibility)
QAccessible::installActivationObserver(this);
+ setAccessible();
#endif
}
diff --git a/src/quicktemplates/qquicktextarea.cpp b/src/quicktemplates/qquicktextarea.cpp
index e776ca6ae34..8da0e2710ea 100644
--- a/src/quicktemplates/qquicktextarea.cpp
+++ b/src/quicktemplates/qquicktextarea.cpp
@@ -122,6 +122,9 @@ using namespace Qt::StringLiterals;
QQuickTextAreaPrivate::QQuickTextAreaPrivate()
{
+#if QT_CONFIG(accessibility)
+ setAccessible();
+#endif
}
QQuickTextAreaPrivate::~QQuickTextAreaPrivate()
diff --git a/src/quicktemplates/qquicktextfield.cpp b/src/quicktemplates/qquicktextfield.cpp
index 090dcf1146b..ab8f2649065 100644
--- a/src/quicktemplates/qquicktextfield.cpp
+++ b/src/quicktemplates/qquicktextfield.cpp
@@ -88,6 +88,7 @@ QQuickTextFieldPrivate::QQuickTextFieldPrivate()
{
#if QT_CONFIG(accessibility)
QAccessible::installActivationObserver(this);
+ setAccessible();
#endif
}
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
index 2d8cb883cda..033cb5736ed 100644
--- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
+++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
@@ -27,6 +27,7 @@
#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QQmlComponent>
+#include <QQmlApplicationEngine>
using namespace Qt::StringLiterals;
@@ -72,6 +73,8 @@ private slots:
void eventTest();
void relations_data();
void relations();
+ void controlsThatShouldSendObjectShow_data();
+ void controlsThatShouldSendObjectShow();
};
tst_QQuickAccessible::tst_QQuickAccessible()
@@ -933,6 +936,55 @@ void tst_QQuickAccessible::relations()
QVERIFY(!otherRelations.isEmpty());
}
+void tst_QQuickAccessible::controlsThatShouldSendObjectShow_data()
+{
+ QTest::addColumn<QByteArray>("qmlSnippet");
+
+ QTest::newRow("BusyIndicator") << QByteArray("BusyIndicator { running: true }");
+ QTest::newRow("Button") << QByteArray("Button { text: 'Button' }");
+ QTest::newRow("ComboBox") << QByteArray("ComboBox { model: 3 }");
+ QTest::newRow("Dial") << QByteArray("Dial { value: 0.5 }");
+ // Label without a text is a bit unusual,
+ // but the background can be an image with meaningful info...
+ QTest::newRow("Label") << QByteArray("Label {\nbackground: Rectangle {\ncolor: 'red'\n}\nwidth: 50\nheight: 20}");
+ QTest::newRow("ProgressBar") << QByteArray("ProgressBar { value: 0.5 }");
+ QTest::newRow("RangeSlider") << QByteArray("RangeSlider { from: 1; to: 100; second.value: 50 }");
+ QTest::newRow("RoundButton") << QByteArray("RoundButton { text: 'Yes, please' }");
+ QTest::newRow("Slider") << QByteArray("Slider { value: 0.5 }");
+ QTest::newRow("Switch") << QByteArray("Switch { text: 'Switch me' }");
+ QTest::newRow("TextArea") << QByteArray("TextArea { width: 50}");
+ QTest::newRow("TextField") << QByteArray("TextField { width: 50}");
+
+ QTest::newRow("CheckBox") << QByteArray("CheckBox { text: 'checkBox' }");
+ QTest::newRow("DelayButton") << QByteArray("DelayButton { text: 'Are you really sure?' }");
+ QTest::newRow("RadioButton") << QByteArray("RadioButton { text: 'RadioButton' }");
+ QTest::newRow("TabButton") << QByteArray("TabButton { text: 'Home' }");
+}
+
+void tst_QQuickAccessible::controlsThatShouldSendObjectShow()
+{
+ QFETCH(QByteArray, qmlSnippet);
+
+ auto clearEvents = qScopeGuard([]{ QTestAccessibility::clearEvents(); });
+ QQmlApplicationEngine engine;
+ engine.loadData(QByteArray(R"(import QtQuick
+import QtQuick.Controls
+Window { visible: true
+)") + qmlSnippet + "}",
+ QUrl());
+
+ QVERIFY(engine.rootObjects().count() > 0);
+ QQuickWindow *window = qobject_cast<QQuickWindow*>(engine.rootObjects().first());
+ QQuickItem *contentItem = window->contentItem();
+ QVERIFY(contentItem);
+ QQuickItem *rootItem = contentItem->childItems().first();
+ QVERIFY(rootItem);
+
+ QAccessibleEvent ev(rootItem, QAccessible::ObjectShow);
+ // Don't use QVERIFY_EVENT, because it gets very noisy when additional events are found
+ QVERIFY(QTestAccessibility::containsEvent(&ev));
+}
+
QTEST_MAIN(tst_QQuickAccessible)
#include "tst_qquickaccessible.moc"
--
GitLab