summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp124
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h2
2 files changed, 56 insertions, 70 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 9ec649394d..e0641a0282 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -82,8 +82,13 @@ extern uint qGlobalPostedEventsCount();
enum {
WM_QT_SOCKETNOTIFIER = WM_USER,
WM_QT_SENDPOSTEDEVENTS = WM_USER + 1,
- WM_QT_ACTIVATENOTIFIERS = WM_USER + 2,
- SendPostedEventsWindowsTimerId = ~1u
+ WM_QT_ACTIVATENOTIFIERS = WM_USER + 2
+};
+
+// WM_QT_SENDPOSTEDEVENTS message parameter
+enum {
+ WMWP_QT_TOFOREIGNLOOP = 0,
+ WMWP_QT_FROMWAKEUP
};
class QEventDispatcherWin32Private;
@@ -96,8 +101,8 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
: threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0),
- getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0),
- wakeUps(0), activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL)
+ getMessageHook(0), wakeUps(0), activateNotifiersPosted(false),
+ winEventNotifierActivatedEvent(NULL)
{
}
@@ -234,22 +239,20 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
return 0;
}
case WM_TIMER:
- if (d->sendPostedEventsWindowsTimerId == 0
- || wp != uint(d->sendPostedEventsWindowsTimerId)) {
- Q_ASSERT(d != 0);
- d->sendTimerEvent(wp);
- return 0;
- }
- // we also use a Windows timer to send posted events when the message queue is full
- Q_FALLTHROUGH();
- case WM_QT_SENDPOSTEDEVENTS: {
- const int localSerialNumber = d->serialNumber.load();
- if (localSerialNumber != d->lastSerialNumber) {
- d->lastSerialNumber = localSerialNumber;
- q->sendPostedEvents();
- }
+ Q_ASSERT(d != 0);
+
+ d->sendTimerEvent(wp);
+ return 0;
+ case WM_QT_SENDPOSTEDEVENTS:
+ Q_ASSERT(d != 0);
+
+ // Allow posting WM_QT_SENDPOSTEDEVENTS message.
+ d->wakeUps.store(0);
+
+ // We send posted events manually, if the window procedure was invoked
+ // by the foreign event loop (e.g. from the native modal dialog).
+ q->sendPostedEvents();
return 0;
- }
} // switch (message)
return DefWindowProc(hwnd, message, wp, lp);
@@ -272,39 +275,6 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
Q_ASSERT(q != 0);
- if (wp == PM_REMOVE) {
- if (q) {
- MSG *msg = (MSG *) lp;
- QEventDispatcherWin32Private *d = q->d_func();
- const int localSerialNumber = d->serialNumber.load();
- static const UINT mask = inputTimerMask();
- if (HIWORD(GetQueueStatus(mask)) == 0) {
- // no more input or timer events in the message queue, we can allow posted events to be sent normally now
- if (d->sendPostedEventsWindowsTimerId != 0) {
- // stop the timer to send posted events, since we now allow the WM_QT_SENDPOSTEDEVENTS message
- KillTimer(d->internalHwnd, d->sendPostedEventsWindowsTimerId);
- d->sendPostedEventsWindowsTimerId = 0;
- }
- (void) d->wakeUps.fetchAndStoreRelease(0);
- if (localSerialNumber != d->lastSerialNumber
- // if this message IS the one that triggers sendPostedEvents(), no need to post it again
- && (msg->hwnd != d->internalHwnd
- || msg->message != WM_QT_SENDPOSTEDEVENTS)) {
- PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
- }
- } else if (d->sendPostedEventsWindowsTimerId == 0
- && localSerialNumber != d->lastSerialNumber) {
- // start a special timer to continue delivering posted events while
- // there are still input and timer messages in the message queue
- d->sendPostedEventsWindowsTimerId = SetTimer(d->internalHwnd,
- SendPostedEventsWindowsTimerId,
- 0, // we specify zero, but Windows uses USER_TIMER_MINIMUM
- NULL);
- // we don't check the return value of SetTimer()... if creating the timer failed, there's little
- // we can do. we just have to accept that posted events will be starved
- }
- }
- }
return q->d_func()->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0;
}
@@ -559,9 +529,12 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
d->interrupt.store(false);
emit awake();
+ // To prevent livelocks, send posted events once per iteration.
+ // QCoreApplication::sendPostedEvents() takes care about recursions.
+ sendPostedEvents();
+
bool canWait;
bool retVal = false;
- bool seenWM_QT_SENDPOSTEDEVENTS = false;
bool needWM_QT_SENDPOSTEDEVENTS = false;
do {
DWORD waitRet = 0;
@@ -615,14 +588,15 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
(void) qt_GetMessageHook(0, PM_REMOVE, reinterpret_cast<LPARAM>(&msg));
if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
- if (seenWM_QT_SENDPOSTEDEVENTS) {
- // when calling processEvents() "manually", we only want to send posted
- // events once
- needWM_QT_SENDPOSTEDEVENTS = true;
- continue;
+ // Set result to 'true', if the message was sent by wakeUp().
+ if (msg.wParam == WMWP_QT_FROMWAKEUP) {
+ d->wakeUps.store(0);
+ retVal = true;
}
- seenWM_QT_SENDPOSTEDEVENTS = true;
- } else if (msg.message == WM_TIMER) {
+ needWM_QT_SENDPOSTEDEVENTS = true;
+ continue;
+ }
+ if (msg.message == WM_TIMER) {
// avoid live-lock by keeping track of the timers we've already sent
bool found = false;
for (int i = 0; !found && i < processedTimers.count(); ++i) {
@@ -639,10 +613,22 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
}
if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) {
+ // Post WM_QT_SENDPOSTEDEVENTS before calling external code,
+ // as it can start a foreign event loop.
+ if (needWM_QT_SENDPOSTEDEVENTS) {
+ needWM_QT_SENDPOSTEDEVENTS = false;
+ PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS,
+ WMWP_QT_TOFOREIGNLOOP, 0);
+ }
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} else if (waitRet - WAIT_OBJECT_0 < nCount) {
+ if (needWM_QT_SENDPOSTEDEVENTS) {
+ needWM_QT_SENDPOSTEDEVENTS = false;
+ PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS,
+ WMWP_QT_TOFOREIGNLOOP, 0);
+ }
activateEventNotifiers();
} else {
// nothing todo so break
@@ -660,19 +646,20 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
emit awake();
if (waitRet - WAIT_OBJECT_0 < nCount) {
+ if (needWM_QT_SENDPOSTEDEVENTS) {
+ needWM_QT_SENDPOSTEDEVENTS = false;
+ PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS,
+ WMWP_QT_TOFOREIGNLOOP, 0);
+ }
activateEventNotifiers();
retVal = true;
}
}
} while (canWait);
- if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) {
- // when called "manually", always send posted events
- sendPostedEvents();
- }
-
if (needWM_QT_SENDPOSTEDEVENTS)
- PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
+ PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS,
+ WMWP_QT_TOFOREIGNLOOP, 0);
return retVal;
}
@@ -1016,10 +1003,11 @@ int QEventDispatcherWin32::remainingTime(int timerId)
void QEventDispatcherWin32::wakeUp()
{
Q_D(QEventDispatcherWin32);
- d->serialNumber.ref();
if (d->internalHwnd && d->wakeUps.testAndSetAcquire(0, 1)) {
// post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending
- PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
+ if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS,
+ WMWP_QT_FROMWAKEUP, 0))
+ qErrnoWarning("QEventDispatcherWin32::wakeUp: Failed to post a message");
}
}
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index dbad2a5450..f672530ff8 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -172,8 +172,6 @@ public:
HHOOK getMessageHook;
// for controlling when to send posted events
- QAtomicInt serialNumber;
- int lastSerialNumber, sendPostedEventsWindowsTimerId;
QAtomicInt wakeUps;
// timers