From a85791ddf5384abd91232a981c8b4aae19ed93da Mon Sep 17 00:00:00 2001 From: Doris Verria Date: Wed, 13 Dec 2023 13:31:13 +0100 Subject: QQuickItem: Respect focusPolicy when delivering events When delivering events that may potentially transfer focus based on the focusPolicy of the item, we need to set the focus (if needed) before letting the item handle the event. Do this in QQuickItem::event so that the specific event handlers don't need to deal with setting focus, as well as overrides don't need to know about those handler's implementations in the base. Task-number: QTBUG-117596 Pick-to: 6.7 Change-Id: I8223638ce4abf80c212dc63bffdb876254e43442 Reviewed-by: Mitch Curtis Reviewed-by: Volker Hilsheimer --- src/quick/items/qquickitem.cpp | 101 ++++++++++++++++++++++++++++++++++------- 1 file changed, 85 insertions(+), 16 deletions(-) (limited to 'src/quick/items/qquickitem.cpp') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 78b14df8f1..44372e8fd6 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -88,6 +88,14 @@ void debugFocusTree(QQuickItem *item, QQuickItem *scope = nullptr, int depth = 1 } } +static void setActiveFocus(QQuickItem *item, Qt::FocusReason reason) +{ + QQuickItemPrivate *d = QQuickItemPrivate::get(item); + if (d->subFocusItem && d->window && d->flags & QQuickItem::ItemIsFocusScope) + QQuickWindowPrivate::get(d->window)->clearFocusInScope(item, d->subFocusItem, reason); + item->forceActiveFocus(reason); +} + /*! \qmltype Transform \instantiates QQuickTransform @@ -1697,6 +1705,40 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) } } + +bool QQuickItemPrivate::setFocusIfNeeded(QEvent::Type eventType) +{ + Q_Q(QQuickItem); + const bool setFocusOnRelease = QGuiApplication::styleHints()->setFocusOnTouchRelease(); + Qt::FocusPolicy policy = Qt::ClickFocus; + + switch (eventType) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + case QEvent::TouchBegin: + if (setFocusOnRelease) + return false; + break; + case QEvent::MouseButtonRelease: + case QEvent::TouchEnd: + if (!setFocusOnRelease) + return false; + break; + case QEvent::Wheel: + policy = Qt::WheelFocus; + break; + default: + break; + } + + if ((focusPolicy & policy) == policy) { + setActiveFocus(q, Qt::MouseFocusReason); + return true; + } + + return false; +} + /*! \class QQuickItem \brief The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}. @@ -5535,6 +5577,41 @@ bool QQuickItemPrivate::filterKeyEvent(QKeyEvent *e, bool post) return e->isAccepted(); } +void QQuickItemPrivate::deliverPointerEvent(QEvent *event) +{ + Q_Q(QQuickItem); + const auto eventType = event->type(); + const bool focusAccepted = setFocusIfNeeded(eventType); + + switch (eventType) { + case QEvent::MouseButtonPress: + q->mousePressEvent(static_cast(event)); + break; + case QEvent::MouseButtonRelease: + q->mouseReleaseEvent(static_cast(event)); + break; + case QEvent::MouseButtonDblClick: + q->mouseDoubleClickEvent(static_cast(event)); + break; +#if QT_CONFIG(wheelevent) + case QEvent::Wheel: + q->wheelEvent(static_cast(event)); + break; +#endif + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::TouchCancel: + q->touchEvent(static_cast(event)); + break; + default: + break; + } + + if (focusAccepted) + event->accept(); +} + void QQuickItemPrivate::deliverKeyEvent(QKeyEvent *e) { Q_Q(QQuickItem); @@ -8918,8 +8995,14 @@ bool QQuickItem::event(QEvent *ev) case QEvent::TouchUpdate: case QEvent::TouchEnd: case QEvent::TouchCancel: - touchEvent(static_cast(ev)); - break; + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: +#if QT_CONFIG(wheelevent) + case QEvent::Wheel: +#endif + d->deliverPointerEvent(ev); + break; case QEvent::StyleAnimationUpdate: if (isVisible()) { ev->accept(); @@ -8951,20 +9034,6 @@ bool QQuickItem::event(QEvent *ev) case QEvent::MouseMove: mouseMoveEvent(static_cast(ev)); break; - case QEvent::MouseButtonPress: - mousePressEvent(static_cast(ev)); - break; - case QEvent::MouseButtonRelease: - mouseReleaseEvent(static_cast(ev)); - break; - case QEvent::MouseButtonDblClick: - mouseDoubleClickEvent(static_cast(ev)); - break; -#if QT_CONFIG(wheelevent) - case QEvent::Wheel: - wheelEvent(static_cast(ev)); - break; -#endif #if QT_CONFIG(quick_draganddrop) case QEvent::DragEnter: dragEnterEvent(static_cast(ev)); -- cgit v1.2.3