diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index d9b9d84e41d..43872fd0270 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -277,9 +277,13 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) Q_ASSERT(q != 0); QEventDispatcherWin32Private *d = q->d_func(); MSG *msg = reinterpret_cast(lp); + // Windows unexpectedly passes PM_NOYIELD flag to the hook procedure, + // if ::PeekMessage(..., PM_REMOVE | PM_NOYIELD) is called from the event loop. + // So, retrieve 'removed' tag as a bit field. + const bool messageRemoved = (wp & PM_REMOVE) != 0; if (msg->hwnd == d->internalHwnd && msg->message == WM_QT_SENDPOSTEDEVENTS - && wp == PM_REMOVE && d->sendPostedEventsTimerId == 0) { + && messageRemoved && d->sendPostedEventsTimerId == 0) { // Start a timer to deliver posted events when the message queue is emptied. d->sendPostedEventsTimerId = SetTimer(d->internalHwnd, SendPostedEventsTimerId, USER_TIMER_MINIMUM, NULL); diff --git a/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp b/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp index 3d1876f00fa..5fd7079a6a9 100644 --- a/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp +++ b/tests/auto/gui/kernel/noqteventloop/tst_noqteventloop.cpp @@ -51,6 +51,7 @@ private slots: void consumeMouseEvents(); void consumeSocketEvents(); void deliverEventsInLivelock(); + void postingWithNoYieldFlag(); }; class Window : public QRasterWindow @@ -341,6 +342,43 @@ void tst_NoQtEventLoop::deliverEventsInLivelock() QVERIFY(!livelockTimer.isActive()); } +void tst_NoQtEventLoop::postingWithNoYieldFlag() +{ + int argc = 1; + char *argv[] = { const_cast("test"), 0 }; + QGuiApplication app(argc, argv); + + bool signalReceived = false; + // Post a message to the queue + QMetaObject::invokeMethod(this, [&signalReceived]() { + signalReceived = true; + }, Qt::QueuedConnection); + + // Post some system messages + QWindow mainWindow; + mainWindow.show(); + + QElapsedTimer elapsedTimer; + elapsedTimer.start(); + + // Exec own message loop + MSG msg; + forever { + if (elapsedTimer.hasExpired(3000) || signalReceived) + break; + + if (!::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) { + QThread::msleep(100); + continue; + } + + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + QVERIFY(signalReceived); +} + #include QTEST_APPLESS_MAIN(tst_NoQtEventLoop)