summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qeventdispatcher_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel/qeventdispatcher_win.cpp')
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp414
1 files changed, 126 insertions, 288 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 7e6d478473..a7663b2481 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -1,63 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qeventdispatcher_win_p.h"
#include "qcoreapplication.h"
#include <private/qsystemlibrary_p.h>
#include "qoperatingsystemversion.h"
-#include "qpair.h"
#include "qset.h"
#include "qsocketnotifier.h"
#include "qvarlengtharray.h"
-#include "qwineventnotifier.h"
#include "qelapsedtimer.h"
#include "qcoreapplication_p.h"
#include <private/qthread_p.h>
-#include <private/qwineventnotifier_p.h>
QT_BEGIN_NAMESPACE
-extern uint qGlobalPostedEventsCount();
-
#ifndef TIME_KILL_SYNCHRONOUS
# define TIME_KILL_SYNCHRONOUS 0x0100
#endif
@@ -96,10 +55,17 @@ class QEventDispatcherWin32Private;
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
+static quint64 qt_msectime()
+{
+ using namespace std::chrono;
+ auto t = duration_cast<milliseconds>(steady_clock::now().time_since_epoch());
+ return t.count();
+}
+
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
- : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0),
- getMessageHook(0), sendPostedEventsTimerId(0), wakeUps(0),
- activateNotifiersPosted(false), activateEventNotifiersPosted(false)
+ : interrupt(false), internalHwnd(0),
+ sendPostedEventsTimerId(0), wakeUps(0),
+ activateNotifiersPosted(false)
{
}
@@ -109,12 +75,6 @@ QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
DestroyWindow(internalHwnd);
}
-void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen)
-{
- QEvent event(QEvent::WinEventAct);
- QCoreApplication::sendEvent(wen, &event);
-}
-
// This function is called by a workerthread
void WINAPI QT_WIN_CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/)
{
@@ -125,18 +85,6 @@ void WINAPI QT_WIN_CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/,
QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId));
}
-static inline UINT inputQueueMask()
-{
- UINT result = QS_ALLEVENTS;
- // QTBUG 28513, QTBUG-29097, QTBUG-29435: QS_TOUCH, QS_POINTER became part of
- // QS_INPUT in Windows Kit 8. They should not be used when running on pre-Windows 8.
-#if WINVER > 0x0601
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8)
- result &= ~(QS_TOUCH | QS_POINTER);
-#endif // WINVER > 0x0601
- return result;
-}
-
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
if (message == WM_NCCREATE)
@@ -157,13 +105,9 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
if (dispatcher->filterNativeEvent(QByteArrayLiteral("windows_dispatcher_MSG"), &msg, &result))
return result;
-#ifdef GWLP_USERDATA
auto q = reinterpret_cast<QEventDispatcherWin32 *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
-#else
- auto q = reinterpret_cast<QEventDispatcherWin32 *>(GetWindowLong(hwnd, GWL_USERDATA));
-#endif
- QEventDispatcherWin32Private *d = 0;
- if (q != 0)
+ QEventDispatcherWin32Private *d = nullptr;
+ if (q != nullptr)
d = q->d_func();
switch (message) {
@@ -187,11 +131,11 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
break;
}
if (type >= 0) {
- Q_ASSERT(d != 0);
+ Q_ASSERT(d != nullptr);
QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read };
QSNDict *dict = sn_vec[type];
- QSockNot *sn = dict ? dict->value(wp) : 0;
+ QSockNot *sn = dict ? dict->value(qintptr(wp)) : 0;
if (sn == nullptr) {
d->postActivateSocketNotifiers();
} else {
@@ -217,7 +161,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
return 0;
}
case WM_QT_ACTIVATENOTIFIERS: {
- Q_ASSERT(d != 0);
+ Q_ASSERT(d != nullptr);
// Postpone activation if we have unhandled socket notifier messages
// in the queue. WM_QT_ACTIVATENOTIFIERS will be posted again as a result of
@@ -242,7 +186,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
return 0;
}
case WM_TIMER:
- Q_ASSERT(d != 0);
+ Q_ASSERT(d != nullptr);
if (wp == d->sendPostedEventsTimerId)
q->sendPostedEvents();
@@ -250,39 +194,32 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
d->sendTimerEvent(wp);
return 0;
case WM_QT_SENDPOSTEDEVENTS:
- Q_ASSERT(d != 0);
+ Q_ASSERT(d != nullptr);
// We send posted events manually, if the window procedure was invoked
// by the foreign event loop (e.g. from the native modal dialog).
// Skip sending, if the message queue is not empty.
// sendPostedEventsTimer will deliver posted events later.
- static const UINT mask = inputQueueMask();
+ static const UINT mask = QS_ALLEVENTS;
if (HIWORD(GetQueueStatus(mask)) == 0)
q->sendPostedEvents();
+ else
+ d->startPostedEventsTimer();
return 0;
} // switch (message)
return DefWindowProc(hwnd, message, wp, lp);
}
-LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
+void QEventDispatcherWin32Private::startPostedEventsTimer()
{
- QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
- Q_ASSERT(q != 0);
- QEventDispatcherWin32Private *d = q->d_func();
- 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
- && messageRemoved && d->sendPostedEventsTimerId == 0) {
+ // we received WM_QT_SENDPOSTEDEVENTS, so allow posting it again
+ wakeUps.storeRelaxed(0);
+ if (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);
+ sendPostedEventsTimerId = SetTimer(internalHwnd, SendPostedEventsTimerId,
+ USER_TIMER_MINIMUM, NULL);
}
- return d->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0;
}
// Provide class name and atom for the message window used by
@@ -354,24 +291,52 @@ static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatch
return 0;
}
-#ifdef GWLP_USERDATA
SetWindowLongPtr(wnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(eventDispatcher));
-#else
- SetWindowLong(wnd, GWL_USERDATA, reinterpret_cast<LONG>(eventDispatcher));
-#endif
return wnd;
}
-static void calculateNextTimeout(WinTimerInfo *t, quint64 currentTime)
+static ULONG calculateNextTimeout(WinTimerInfo *t, quint64 currentTime)
{
uint interval = t->interval;
- if ((interval >= 20000u && t->timerType != Qt::PreciseTimer) || t->timerType == Qt::VeryCoarseTimer) {
- // round the interval, VeryCoarseTimers only have full second accuracy
- interval = ((interval + 500)) / 1000 * 1000;
+ ULONG tolerance = TIMERV_DEFAULT_COALESCING;
+ switch (t->timerType) {
+ case Qt::PreciseTimer:
+ // high precision timer is based on millisecond precision
+ // so no adjustment is necessary
+ break;
+
+ case Qt::CoarseTimer:
+ // this timer has up to 5% coarseness
+ // so our boundaries are 20 ms and 20 s
+ // below 20 ms, 5% inaccuracy is below 1 ms, so we convert to high precision
+ // above 20 s, 5% inaccuracy is above 1 s, so we convert to VeryCoarseTimer
+ if (interval >= 20000) {
+ t->timerType = Qt::VeryCoarseTimer;
+ } else if (interval <= 20) {
+ // no adjustment necessary
+ t->timerType = Qt::PreciseTimer;
+ break;
+ } else {
+ tolerance = interval / 20;
+ break;
+ }
+ Q_FALLTHROUGH();
+ case Qt::VeryCoarseTimer:
+ // the very coarse timer is based on full second precision,
+ // so we round to closest second (but never to zero)
+ tolerance = 1000;
+ if (interval < 1000)
+ interval = 1000;
+ else
+ interval = (interval + 500) / 1000 * 1000;
+ currentTime = currentTime / 1000 * 1000;
+ break;
}
+
t->interval = interval;
t->timeout = currentTime + interval;
+ return tolerance;
}
void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
@@ -381,13 +346,13 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
Q_Q(QEventDispatcherWin32);
bool ok = false;
- calculateNextTimeout(t, qt_msectime());
+ ULONG tolerance = calculateNextTimeout(t, qt_msectime());
uint interval = t->interval;
if (interval == 0u) {
// optimization for single-shot-zero-timer
QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
ok = true;
- } else if (interval < 20u || t->timerType == Qt::PreciseTimer) {
+ } else if (tolerance == TIMERV_DEFAULT_COALESCING) {
// 3/2016: Although MSDN states timeSetEvent() is deprecated, the function
// is still deemed to be the most reliable precision timer.
t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc, DWORD_PTR(t),
@@ -397,8 +362,10 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
if (!ok) {
// user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
- ok = SetTimer(internalHwnd, t->timerId, interval, 0);
+ ok = SetCoalescableTimer(internalHwnd, t->timerId, interval, nullptr, tolerance);
}
+ if (!ok)
+ ok = SetTimer(internalHwnd, t->timerId, interval, nullptr);
if (!ok)
qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
@@ -411,7 +378,7 @@ void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
} else if (t->fastTimerId != 0) {
timeKillEvent(t->fastTimerId);
QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
- } else if (internalHwnd) {
+ } else {
KillTimer(internalHwnd, t->timerId);
}
t->timerId = -1;
@@ -441,7 +408,7 @@ void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
}
}
-void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket, long event)
+void QEventDispatcherWin32Private::doWsaAsyncSelect(qintptr socket, long event)
{
Q_ASSERT(internalHwnd);
// BoundsChecker may emit a warning for WSAAsyncSelect when event == 0
@@ -455,44 +422,19 @@ void QEventDispatcherWin32Private::postActivateSocketNotifiers()
activateNotifiersPosted = PostMessage(internalHwnd, WM_QT_ACTIVATENOTIFIERS, 0, 0);
}
-void QEventDispatcherWin32Private::postActivateEventNotifiers()
+QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
+ : QEventDispatcherWin32(*new QEventDispatcherWin32Private, parent)
{
- Q_Q(QEventDispatcherWin32);
-
- if (!activateEventNotifiersPosted.fetchAndStoreRelease(true))
- QCoreApplication::postEvent(q, new QEvent(QEvent::WinEventAct));
}
-void QEventDispatcherWin32::createInternalHwnd()
+QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
+ : QAbstractEventDispatcher(dd, parent)
{
Q_D(QEventDispatcherWin32);
- if (d->internalHwnd)
- return;
d->internalHwnd = qt_create_internal_window(this);
-
- // setup GetMessage hook needed to drive our posted events
- d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
- if (Q_UNLIKELY(!d->getMessageHook)) {
- int errorCode = GetLastError();
- qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %ls",
- errorCode, qUtf16Printable(qt_error_string(errorCode)));
- }
-
- // start all normal timers
- for (int i = 0; i < d->timerVec.count(); ++i)
- d->registerTimer(d->timerVec.at(i));
-}
-
-QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
- : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent)
-{
}
-QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
- : QAbstractEventDispatcher(dd, parent)
-{ }
-
QEventDispatcherWin32::~QEventDispatcherWin32()
{
}
@@ -517,18 +459,18 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherWin32);
- if (!d->internalHwnd) {
- createInternalHwnd();
- wakeUp(); // trigger a call to sendPostedEvents()
- }
-
- d->interrupt.storeRelaxed(false);
+ // We don't know _when_ the interrupt occurred so we have to honor it.
+ const bool wasInterrupted = d->interrupt.fetchAndStoreRelaxed(false);
emit awake();
// To prevent livelocks, send posted events once per iteration.
// QCoreApplication::sendPostedEvents() takes care about recursions.
sendPostedEvents();
+ if (wasInterrupted)
+ return false;
+
+ auto threadData = d->threadData.loadRelaxed();
bool canWait;
bool retVal = false;
do {
@@ -539,7 +481,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
// process queued user input events
msg = d->queuedUserInputEvents.takeFirst();
- } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
+ } else if (!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
// process queued socket events
msg = d->queuedSocketEvents.takeFirst();
} else if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
@@ -565,6 +507,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
}
if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
+ d->startPostedEventsTimer();
// Set result to 'true' because the message was sent by wakeUp().
retVal = true;
continue;
@@ -599,7 +542,8 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
// wait for message
canWait = (!retVal
&& !d->interrupt.loadRelaxed()
- && (flags & QEventLoop::WaitForMoreEvents));
+ && flags.testFlag(QEventLoop::WaitForMoreEvents)
+ && threadData->canWaitLocked());
if (canWait) {
emit aboutToBlock();
MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
@@ -610,16 +554,10 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
return retVal;
}
-bool QEventDispatcherWin32::hasPendingEvents()
-{
- MSG msg;
- return qGlobalPostedEventsCount() || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
-}
-
void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
- int sockfd = notifier->socket();
+ qintptr sockfd = notifier->socket();
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (sockfd < 0) {
@@ -643,11 +581,9 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
const char *t[] = { "Read", "Write", "Exception" };
/* Variable "socket" below is a function pointer. */
qWarning("QSocketNotifier: Multiple socket notifiers for "
- "same socket %d and type %s", sockfd, t[type]);
+ "same socket %" PRIdQINTPTR " and type %s", sockfd, t[type]);
}
- createInternalHwnd();
-
QSockNot *sn = new QSockNot;
sn->obj = notifier;
sn->fd = sockfd;
@@ -670,9 +606,16 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
}
sd.event |= event;
} else {
- // Disable the events which could be implicitly re-enabled. Next activation
- // of socket notifiers will reset the mask.
- d->active_fd.insert(sockfd, QSockFd(event, FD_READ | FD_ACCEPT | FD_WRITE | FD_OOB));
+ // Although WSAAsyncSelect(..., 0), which is called from
+ // unregisterSocketNotifier(), immediately disables event message
+ // posting for the socket, it is possible that messages could be
+ // waiting in the application message queue even if the socket was
+ // closed. Also, some events could be implicitly re-enabled due
+ // to system calls. Ignore these superfluous events until all
+ // pending notifications have been suppressed. Next activation of
+ // socket notifiers will reset the mask.
+ d->active_fd.insert(sockfd, QSockFd(event, FD_READ | FD_CLOSE | FD_ACCEPT | FD_WRITE
+ | FD_CONNECT | FD_OOB));
}
d->postActivateSocketNotifiers();
@@ -682,7 +625,7 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
#ifndef QT_NO_DEBUG
- int sockfd = notifier->socket();
+ qintptr sockfd = notifier->socket();
if (sockfd < 0) {
qWarning("QEventDispatcherWin32::unregisterSocketNotifier: invalid socket identifier");
return;
@@ -699,7 +642,7 @@ void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier
{
Q_D(QEventDispatcherWin32);
int type = notifier->type();
- int sockfd = notifier->socket();
+ qintptr sockfd = notifier->socket();
Q_ASSERT(sockfd >= 0);
QSFDict::iterator it = d->active_fd.find(sockfd);
@@ -727,7 +670,7 @@ void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier
delete sn;
}
-void QEventDispatcherWin32::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
+void QEventDispatcherWin32::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object)
{
#ifndef QT_NO_DEBUG
if (timerId < 1 || interval < 0 || !object) {
@@ -756,10 +699,8 @@ void QEventDispatcherWin32::registerTimer(int timerId, int interval, Qt::TimerTy
t->inTimerEvent = false;
t->fastTimerId = 0;
- if (d->internalHwnd)
- d->registerTimer(t);
+ d->registerTimer(t);
- d->timerVec.append(t); // store in timer vector
d->timerDict.insert(t->timerId, t); // store timers in dict
}
@@ -777,15 +718,11 @@ bool QEventDispatcherWin32::unregisterTimer(int timerId)
#endif
Q_D(QEventDispatcherWin32);
- if (d->timerVec.isEmpty() || timerId <= 0)
- return false;
- WinTimerInfo *t = d->timerDict.value(timerId);
+ WinTimerInfo *t = d->timerDict.take(timerId);
if (!t)
return false;
- d->timerDict.remove(t->timerId);
- d->timerVec.removeAll(t);
d->unregisterTimer(t);
return true;
}
@@ -804,16 +741,18 @@ bool QEventDispatcherWin32::unregisterTimers(QObject *object)
#endif
Q_D(QEventDispatcherWin32);
- if (d->timerVec.isEmpty())
+ if (d->timerDict.isEmpty())
return false;
- WinTimerInfo *t;
- for (int i=0; i<d->timerVec.size(); i++) {
- t = d->timerVec.at(i);
- if (t && t->obj == object) { // object found
- d->timerDict.remove(t->timerId);
- d->timerVec.removeAt(i);
+
+ auto it = d->timerDict.begin();
+ while (it != d->timerDict.end()) {
+ WinTimerInfo *t = it.value();
+ Q_ASSERT(t);
+ if (t->obj == object) {
+ it = d->timerDict.erase(it);
d->unregisterTimer(t);
- --i;
+ } else {
+ ++it;
}
}
return true;
@@ -831,92 +770,14 @@ QEventDispatcherWin32::registeredTimers(QObject *object) const
Q_D(const QEventDispatcherWin32);
QList<TimerInfo> list;
- for (const WinTimerInfo *t : qAsConst(d->timerVec)) {
- if (t && t->obj == object)
+ for (WinTimerInfo *t : std::as_const(d->timerDict)) {
+ Q_ASSERT(t);
+ if (t->obj == object)
list << TimerInfo(t->timerId, t->interval, t->timerType);
}
return list;
}
-bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier)
-{
- Q_ASSERT(notifier);
-#ifndef QT_NO_DEBUG
- if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QEventDispatcherWin32: event notifiers cannot be enabled from another thread");
- return false;
- }
-#endif
-
- Q_D(QEventDispatcherWin32);
-
- if (d->winEventNotifierList.contains(notifier))
- return true;
-
- createInternalHwnd();
-
- d->winEventNotifierList.append(notifier);
- d->winEventNotifierListModified = true;
-
- return QWinEventNotifierPrivate::get(notifier)->registerWaitObject();
-}
-
-void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier)
-{
- Q_ASSERT(notifier);
-#ifndef QT_NO_DEBUG
- if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QEventDispatcherWin32: event notifiers cannot be disabled from another thread");
- return;
- }
-#endif
- doUnregisterEventNotifier(notifier);
-}
-
-void QEventDispatcherWin32::doUnregisterEventNotifier(QWinEventNotifier *notifier)
-{
- Q_D(QEventDispatcherWin32);
-
- int i = d->winEventNotifierList.indexOf(notifier);
- if (i == -1)
- return;
- d->winEventNotifierList.takeAt(i);
- d->winEventNotifierListModified = true;
- QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
- if (nd->waitHandle)
- nd->unregisterWaitObject();
-}
-
-void QEventDispatcherWin32::activateEventNotifiers()
-{
- Q_D(QEventDispatcherWin32);
-
- // Enable WM_QT_ACTIVATEWINEVENTS posting.
- d->activateEventNotifiersPosted.fetchAndStoreAcquire(false);
-
- // Activate signaled notifiers. Our winEventNotifierList can be modified in activation slots.
- do {
- d->winEventNotifierListModified = false;
- for (int i = 0; i < d->winEventNotifierList.count(); ++i) {
- QWinEventNotifier *notifier = d->winEventNotifierList.at(i);
- QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
- if (nd->signaledCount.loadRelaxed() != 0) {
- --nd->signaledCount;
- nd->unregisterWaitObject();
- d->activateEventNotifier(notifier);
- }
- }
- } while (d->winEventNotifierListModified);
-
- // Re-register the remaining activated notifiers.
- for (int i = 0; i < d->winEventNotifierList.count(); ++i) {
- QWinEventNotifier *notifier = d->winEventNotifierList.at(i);
- QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
- if (!nd->waitHandle)
- nd->registerWaitObject();
- }
-}
-
int QEventDispatcherWin32::remainingTime(int timerId)
{
#ifndef QT_NO_DEBUG
@@ -928,20 +789,12 @@ int QEventDispatcherWin32::remainingTime(int timerId)
Q_D(QEventDispatcherWin32);
- if (d->timerVec.isEmpty())
- return -1;
-
quint64 currentTime = qt_msectime();
- for (const WinTimerInfo *t : qAsConst(d->timerVec)) {
- if (t && t->timerId == timerId) {
- // timer found, return time to wait
-
- if (d->internalHwnd)
- return t->timeout > currentTime ? t->timeout - currentTime : 0;
- else
- return t->interval;
- }
+ WinTimerInfo *t = d->timerDict.value(timerId);
+ if (t) {
+ // timer found, return time to wait
+ return t->timeout > currentTime ? t->timeout - currentTime : 0;
}
#ifndef QT_NO_DEBUG
@@ -954,7 +807,7 @@ int QEventDispatcherWin32::remainingTime(int timerId)
void QEventDispatcherWin32::wakeUp()
{
Q_D(QEventDispatcherWin32);
- if (d->internalHwnd && d->wakeUps.testAndSetRelaxed(0, 1)) {
+ if (d->wakeUps.testAndSetRelaxed(0, 1)) {
// post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending
if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0))
qErrnoWarning("QEventDispatcherWin32::wakeUp: Failed to post a message");
@@ -968,9 +821,6 @@ void QEventDispatcherWin32::interrupt()
wakeUp();
}
-void QEventDispatcherWin32::flush()
-{ }
-
void QEventDispatcherWin32::startingUp()
{ }
@@ -987,22 +837,13 @@ void QEventDispatcherWin32::closingDown()
doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj);
Q_ASSERT(d->active_fd.isEmpty());
- // clean up any eventnotifiers
- while (!d->winEventNotifierList.isEmpty())
- doUnregisterEventNotifier(d->winEventNotifierList.first());
-
// clean up any timers
- for (int i = 0; i < d->timerVec.count(); ++i)
- d->unregisterTimer(d->timerVec.at(i));
- d->timerVec.clear();
+ for (WinTimerInfo *t : std::as_const(d->timerDict))
+ d->unregisterTimer(t);
d->timerDict.clear();
d->closingDown = true;
- if (d->getMessageHook)
- UnhookWindowsHookEx(d->getMessageHook);
- d->getMessageHook = 0;
-
if (d->sendPostedEventsTimerId != 0)
KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
d->sendPostedEventsTimerId = 0;
@@ -1038,9 +879,6 @@ bool QEventDispatcherWin32::event(QEvent *e)
case QEvent::Timer:
d->sendTimerEvent(static_cast<const QTimerEvent*>(e)->timerId());
break;
- case QEvent::WinEventAct:
- activateEventNotifiers();
- break;
default:
break;
}
@@ -1063,9 +901,9 @@ void QEventDispatcherWin32::sendPostedEvents()
HWND QEventDispatcherWin32::internalHwnd()
{
- Q_D(QEventDispatcherWin32);
- createInternalHwnd();
- return d->internalHwnd;
+ return d_func()->internalHwnd;
}
QT_END_NAMESPACE
+
+#include "moc_qeventdispatcher_win_p.cpp"