[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1107340: marked as done (unblock: kf6-kcmutils/6.13.0-2)



Your message dated Fri, 06 Jun 2025 06:44:26 +0000
with message-id <E1uNQoU-007wAZ-1E@respighi.debian.org>
and subject line unblock kf6-kcmutils
has caused the Debian Bug report #1107340,
regarding unblock: kf6-kcmutils/6.13.0-2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1107340: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1107340
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
X-Debbugs-Cc: kf6-kcmutils@packages.debian.org, Debian Qt/KDE Maintainers <debian-qt-kde@lists.debian.org>
Control: affects -1 + src:kf6-kcmutils
User: release.debian.org@packages.debian.org
Usertags: unblock

Dear Release Team,

please unblock package kf6-kcmutils.

[ Reason ]
It contains the following changes:
* Backport upstream commit:
  - Improved accessibility by screen readers and keyboard navigation
  throughout System Settings, particularly around the topics of passing
  focus between page content and the window’s sidebars and footers.

[ Tests ]
Tested that systemsettings pages display correctly and keyboard
navigation works.
Upstream testsuite passes.

[ Risks ]
Only backport of upstream commits that apply cleanly. Further fixes can
easily be backported or the changes reverted.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing


Thanks!


unblock kf6-kcmutils/6.13.0-2
diff -Nru kf6-kcmutils-6.13.0/debian/changelog kf6-kcmutils-6.13.0/debian/changelog
--- kf6-kcmutils-6.13.0/debian/changelog	2025-04-12 19:37:44.000000000 +0200
+++ kf6-kcmutils-6.13.0/debian/changelog	2025-06-02 23:31:03.000000000 +0200
@@ -1,3 +1,13 @@
+kf6-kcmutils (6.13.0-2) unstable; urgency=medium
+
+  [ Aurélien COUDERC ]
+  * Backport upstream commit:
+    - Improved accessibility by screen readers and keyboard navigation
+    throughout System Settings, particularly around the topics of passing
+    focus between page content and the window’s sidebars and footers.
+
+ -- Aurélien COUDERC <coucouf@debian.org>  Mon, 02 Jun 2025 23:31:03 +0200
+
 kf6-kcmutils (6.13.0-1) unstable; urgency=medium
 
   [ Patrick Franz ]
diff -Nru kf6-kcmutils-6.13.0/debian/patches/series kf6-kcmutils-6.13.0/debian/patches/series
--- kf6-kcmutils-6.13.0/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
+++ kf6-kcmutils-6.13.0/debian/patches/series	2025-06-02 23:29:50.000000000 +0200
@@ -0,0 +1 @@
+upstream_6dc76c3d_kcmoduleqml-simplify-and-improve-focus-handling.patch
diff -Nru kf6-kcmutils-6.13.0/debian/patches/upstream_6dc76c3d_kcmoduleqml-simplify-and-improve-focus-handling.patch kf6-kcmutils-6.13.0/debian/patches/upstream_6dc76c3d_kcmoduleqml-simplify-and-improve-focus-handling.patch
--- kf6-kcmutils-6.13.0/debian/patches/upstream_6dc76c3d_kcmoduleqml-simplify-and-improve-focus-handling.patch	1970-01-01 01:00:00.000000000 +0100
+++ kf6-kcmutils-6.13.0/debian/patches/upstream_6dc76c3d_kcmoduleqml-simplify-and-improve-focus-handling.patch	2025-06-02 23:29:50.000000000 +0200
@@ -0,0 +1,137 @@
+From 6dc76c3dc14aaaecc926a0af8f092402b23bf22b Mon Sep 17 00:00:00 2001
+From: Christoph Wolk <cwo.kde@posteo.net>
+Date: Sat, 8 Feb 2025 18:21:50 +0100
+Subject: [PATCH] kcmoduleqml: simplify and improve focus handling
+
+kcmoduleqml contains some old tricks to make passing focus between the
+qml and qtwidgets bits, but they are fragile, and break in many cases -
+especially with systemsettings adding another layer of qml. The hacks
+may have been necessary in the past, but things actually work well now,
+so we can essentially just set a focusProxy and be done ... as long as
+we don't care about accessibility. The qml bits receive focus before the
+widgets parts fully hand it over, so the first qml item receiving focus
+will not be  announced over screen readers. We do care though, and thus
+some special handling is still needed.
+
+We switch to using focusProxy, and add a bit of surgery to the focus
+transition so that screen readers always stay in the loop about what
+things are focused. We also need a bit of special handling for the
+backtab case, which doesn't quite work automatically with
+activeFocusOnTab set on the qml root.
+---
+ src/kcmoduleqml.cpp | 60 ++++++++++++++++++++++++++++-----------------
+ 1 file changed, 38 insertions(+), 22 deletions(-)
+
+diff --git a/src/kcmoduleqml.cpp b/src/kcmoduleqml.cpp
+index 5666029f..35ac1e54 100644
+--- a/src/kcmoduleqml.cpp
++++ b/src/kcmoduleqml.cpp
+@@ -10,6 +10,7 @@
+ #include <QQuickItem>
+ #include <QQuickWidget>
+ #include <QQuickWindow>
++#include <QTimer>
+ #include <QVBoxLayout>
+ 
+ #include <KAboutData>
+@@ -20,6 +21,7 @@
+ #include "quick/kquickconfigmodule.h"
+ 
+ #include <kcmutils_debug.h>
++#include <qquickitem.h>
+ 
+ class QmlConfigModuleWidget;
+ class KCModuleQmlPrivate
+@@ -64,15 +66,6 @@ public:
+         setFocusPolicy(Qt::StrongFocus);
+     }
+ 
+-    void focusInEvent(QFocusEvent *event) override
+-    {
+-        if (event->reason() == Qt::TabFocusReason) {
+-            m_module->d->rootPlaceHolder->nextItemInFocusChain(true)->forceActiveFocus(Qt::TabFocusReason);
+-        } else if (event->reason() == Qt::BacktabFocusReason) {
+-            m_module->d->rootPlaceHolder->nextItemInFocusChain(false)->forceActiveFocus(Qt::BacktabFocusReason);
+-        }
+-    }
+-
+     QSize sizeHint() const override
+     {
+         if (!m_module->d->rootPlaceHolder) {
+@@ -84,21 +77,45 @@ public:
+ 
+     bool eventFilter(QObject *watched, QEvent *event) override
+     {
+-        if (watched == m_module->d->rootPlaceHolder && event->type() == QEvent::FocusIn) {
++        // Everything would work mosty without manual intervention, but as of Qt 6.8
++        // things require special attention so that they work correctly with orca.
++        // The timing between the focusproxied QQuickWidget receiving focus and the
++        // focused qml Item being registered as focused is off and screen readers get
++        // confused. Instead, put initial focus on the root element and switch with a timer
++        // so the qml focuschange happens while the qquickwidget has focus. This
++        // requires activeFocusOnTab on the rootPlaceHolder to work, and that makes other things
++        // a bit messier than they would otherwise need to be.
++        if (event->type() == QEvent::FocusIn && watched == m_module->d->rootPlaceHolder) {
+             auto focusEvent = static_cast<QFocusEvent *>(event);
+             if (focusEvent->reason() == Qt::TabFocusReason) {
+-                QWidget *w = m_module->d->quickWidget->nextInFocusChain();
+-                while (!w->isEnabled() || !(w->focusPolicy() & Qt::TabFocus)) {
+-                    w = w->nextInFocusChain();
+-                }
+-                w->setFocus(Qt::TabFocusReason); // allow tab navigation inside the qquickwidget
++                m_module->d->rootPlaceHolder->forceActiveFocus(Qt::OtherFocusReason);
++                QTimer::singleShot(0, this, [this] {
++                    QQuickItem *nextItem = m_module->d->rootPlaceHolder->nextItemInFocusChain(true);
++                    if (nextItem) {
++                        nextItem->forceActiveFocus(Qt::TabFocusReason);
++                    }
++                });
+                 return true;
+             } else if (focusEvent->reason() == Qt::BacktabFocusReason) {
+-                QWidget *w = m_module->d->quickWidget->previousInFocusChain();
+-                while (!w->isEnabled() || !(w->focusPolicy() & Qt::TabFocus)) {
+-                    w = w->previousInFocusChain();
++                // this can either happen from backtabbing in qml or from backtabbing
++                // from qwidgets past the focusproxy (e.g. from the kcm buttons).
++                if (!m_module->d->rootPlaceHolder->hasActiveFocus()) {
++                    // we're in widgets, enter qml from reverse in the focus chain in the same way as above
++                    QTimer::singleShot(0, this, [this] {
++                        QQuickItem *nextItem = m_module->d->rootPlaceHolder->nextItemInFocusChain(false);
++                        if (nextItem) {
++                            nextItem->forceActiveFocus(Qt::TabFocusReason);
++                        }
++                    });
++                    return true;
+                 }
+-                w->setFocus(Qt::BacktabFocusReason);
++                // we're coming from qml, so we focus the widget outside. This also needs singleShot;
++                // if we do it immediately, focus cycles backward along the qml focus chain instead.
++                // Without activeFocusOnTab on the rootPlaceHolder we could just return false and
++                // Qt would handle everything by itself
++                QTimer::singleShot(0, this, [this] {
++                    focusNextPrevChild(false);
++                });
+                 return true;
+             }
+         }
+@@ -146,15 +163,14 @@ KCModuleQml::KCModuleQml(KQuickConfigModule *configModule, QWidget *parent)
+ 
+     d->quickWidget = new QQuickWidget(d->configModule->engine().get(), d->widget);
+     d->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+-    d->quickWidget->setFocusPolicy(Qt::StrongFocus);
+     d->quickWidget->setAttribute(Qt::WA_AlwaysStackOnTop, true);
+     d->quickWidget->setAttribute(Qt::WA_NoMousePropagation, true); // Workaround for QTBUG-109861 to fix drag everywhere
+     d->quickWindow = d->quickWidget->quickWindow();
+     d->quickWindow->setColor(Qt::transparent);
++    d->widget->setFocusProxy(d->quickWidget);
+ 
+     QQmlComponent *component = new QQmlComponent(d->configModule->engine().get(), this);
+-    // this has activeFocusOnTab to notice when the navigation wraps
+-    // around, so when we need to go outside and inside
++    // activeFocusOnTab is required to have screen readers not get confused
+     // pushPage/popPage are needed as push of StackView can't be directly invoked from c++
+     // because its parameters are QQmlV4Function which is not public.
+     // The managers of onEnter/ReturnPressed are a workaround of
+-- 
+GitLab
+

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply to: