From c20a382023dde5e2627f3b7ecfcd22e02afc26b4 Mon Sep 17 00:00:00 2001 From: Axel Spoerl Date: Tue, 24 Sep 2024 08:18:47 +0200 Subject: [PATCH] Send events as spontaneous in QWindowPrivate::forwardToPopup() QWindowPrivate::forwardToPopup() sends key events with QCoreApplication::sendEvent(), which sets QEvent::m_spont to false. That makes key and pointer events sent to popups appear synthetic, while they are sponaneous if sent to other widgets. The method has been newly implemented in the course of moving popup handling from QApplication to QGuiApplication. Make current behavior consistent to the behavior prior to e4ef0f03e6f1fddc397980fd7fbf6f6b829f16d9. Since events are always spontaneous, use QCoreApplication::sendSpontaneousEvent() instead. Add a test function to tst_QComboBox to Verify, that key events - are sent directly to the popup - not seen by the window - appear as spontaneous. This amends e4ef0f03e6f1fddc397980fd7fbf6f6b829f16d9. Fixes: QTBUG-129258 Pick-to: 6.8.0 Change-Id: Iff61b98b290f6483948007b5f12b19393759d9db Reviewed-by: Volker Hilsheimer (cherry picked from commit 3fbae61ea245291cb4c34e9126562c307741a600) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/kernel/qcoreapplication.h | 1 + src/gui/kernel/qwindow.cpp | 4 +- .../widgets/qcombobox/tst_qcombobox.cpp | 49 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index 0078dc32958..e27086aa052 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -238,6 +238,7 @@ private: friend class QWidget; friend class QWidgetWindow; friend class QWidgetPrivate; + friend class QWindowPrivate; #ifndef QT_NO_QOBJECT friend class QEventDispatcherUNIXPrivate; friend class QCocoaEventDispatcherPrivate; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index f698113ed29..f950ad1d08e 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2449,7 +2449,7 @@ const QWindow *QWindowPrivate::forwardToPopup(QEvent *event, const QWindow */*ac /* Popups are expected to be able to directly handle the drag-release sequence after pressing to open, as well as any other mouse events that occur within the popup's bounds. */ - if (QCoreApplication::sendEvent(popupWindow, pointerEvent.get())) { + if (QCoreApplication::sendSpontaneousEvent(popupWindow, pointerEvent.get())) { event->setAccepted(pointerEvent->isAccepted()); if (pointerEvent->isAccepted()) ret = popupWindow; @@ -2458,7 +2458,7 @@ const QWindow *QWindowPrivate::forwardToPopup(QEvent *event, const QWindow */*ac << "handled?" << (ret != nullptr) << event->isAccepted(); return ret; } else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { - if (QCoreApplication::sendEvent(popupWindow, event)) + if (QCoreApplication::sendSpontaneousEvent(popupWindow, event)) ret = popupWindow; qCDebug(lcPopup) << q << "forwarded" << event->type() << "to popup" << popupWindow << "handled?" << (ret != nullptr) << event->isAccepted(); diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index 679b824ce50..7936eb78e4e 100644 --- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -104,6 +104,7 @@ private slots: void mouseWheel(); void popupWheelHandling(); #endif // QT_CONFIG(wheelevent) + void sendKeyEventToPopup(); void layoutDirection(); void itemListPosition(); void separatorItem_data(); @@ -2185,6 +2186,54 @@ void tst_QComboBox::popupWheelHandling() } #endif // QT_CONFIG(wheelevent) +void tst_QComboBox::sendKeyEventToPopup() +{ + struct KeyEventFilter : public QObject { + uint countWindow = 0; + uint countView = 0; + bool eventFilter(QObject *obj, QEvent *event) override + { + if (event->type() != QEvent::KeyPress) + return false; + + if (qobject_cast(obj)) + ++countWindow; + + if (qobject_cast(obj) && event->spontaneous()) + ++countView; + + return false; + } + }; + + QScrollArea scrollArea; + scrollArea.move(300, 300); + QWidget *widget = new QWidget; + scrollArea.setWidget(widget); + QVBoxLayout *layout = new QVBoxLayout(widget); + layout->setSizeConstraint(QLayout::SetMinAndMaxSize); + QComboBox *comboBox = new QComboBox; + comboBox->addItems(QStringList() << QStringLiteral("Won") << QStringLiteral("Too") + << QStringLiteral("3") << QStringLiteral("fore")); + layout->addWidget(comboBox); + layout->addSpacing(100); + const QPoint sizeP(scrollArea.width(), scrollArea.height()); + scrollArea.move(QGuiApplication::primaryScreen()->availableGeometry().center() - sizeP / 2); + scrollArea.show(); + QVERIFY(QTest::qWaitForWindowExposed(&scrollArea)); + comboBox->showPopup(); + auto *itemView = comboBox->findChild(); + QVERIFY(QTest::qWaitForWindowExposed(itemView)); + KeyEventFilter filter; + itemView->installEventFilter(&filter); + comboBox->window()->windowHandle()->installEventFilter(&filter); + QWindowSystemInterfacePrivate::KeyEvent ke(comboBox->window()->windowHandle(), 0, QEvent::KeyPress, Qt::Key_End, Qt::KeyboardModifiers()); + QGuiApplicationPrivate::processKeyEvent(&ke); + // Make sure that the key event is directly delivered to the popup + QCOMPARE(filter.countWindow, 0); + QCOMPARE(filter.countView, 1); +} + void tst_QComboBox::layoutDirection() { QComboBox box;