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 <volker.hilsheimer@qt.io>
(cherry picked from commit 3fbae61ea245291cb4c34e9126562c307741a600)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Axel Spoerl 2024-09-24 08:18:47 +02:00 committed by Qt Cherry-pick Bot
parent 5b697bb08c
commit c20a382023
3 changed files with 52 additions and 2 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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<QWindow *>(obj))
++countWindow;
if (qobject_cast<QAbstractItemView *>(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<QAbstractItemView *>();
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;