QEventDispatcherWin32: retrieve PM_REMOVE value as a bit flag
Windows unexpectedly passes PM_NOYIELD flag in wParam parameter to the hook procedure, if ::PeekMessage(..., PM_REMOVE | PM_NOYIELD) is called from the event loop. So, to ignore undocumented flag, we should interpret wParam as a bit field. Thanks to Robin Lobel for research. Pick-to: 5.15 Fixes: QTBUG-84562 Change-Id: Ib16d7d747aebc9a3628e4ee67478c4d3edeb96f1 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
parent
b99ade85b0
commit
33e6e5fac3
@ -277,9 +277,13 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
|
|||||||
Q_ASSERT(q != 0);
|
Q_ASSERT(q != 0);
|
||||||
QEventDispatcherWin32Private *d = q->d_func();
|
QEventDispatcherWin32Private *d = q->d_func();
|
||||||
MSG *msg = reinterpret_cast<MSG *>(lp);
|
MSG *msg = reinterpret_cast<MSG *>(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
|
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.
|
// Start a timer to deliver posted events when the message queue is emptied.
|
||||||
d->sendPostedEventsTimerId = SetTimer(d->internalHwnd, SendPostedEventsTimerId,
|
d->sendPostedEventsTimerId = SetTimer(d->internalHwnd, SendPostedEventsTimerId,
|
||||||
USER_TIMER_MINIMUM, NULL);
|
USER_TIMER_MINIMUM, NULL);
|
||||||
|
@ -51,6 +51,7 @@ private slots:
|
|||||||
void consumeMouseEvents();
|
void consumeMouseEvents();
|
||||||
void consumeSocketEvents();
|
void consumeSocketEvents();
|
||||||
void deliverEventsInLivelock();
|
void deliverEventsInLivelock();
|
||||||
|
void postingWithNoYieldFlag();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Window : public QRasterWindow
|
class Window : public QRasterWindow
|
||||||
@ -341,6 +342,43 @@ void tst_NoQtEventLoop::deliverEventsInLivelock()
|
|||||||
QVERIFY(!livelockTimer.isActive());
|
QVERIFY(!livelockTimer.isActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_NoQtEventLoop::postingWithNoYieldFlag()
|
||||||
|
{
|
||||||
|
int argc = 1;
|
||||||
|
char *argv[] = { const_cast<char *>("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 <tst_noqteventloop.moc>
|
#include <tst_noqteventloop.moc>
|
||||||
|
|
||||||
QTEST_APPLESS_MAIN(tst_NoQtEventLoop)
|
QTEST_APPLESS_MAIN(tst_NoQtEventLoop)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user