216void QEventDispatcherWin32Private::startPostedEventsTimer()
219 wakeUps.storeRelaxed(0);
220 if (sendPostedEventsTimerId == 0) {
222 sendPostedEventsTimerId = SetTimer(internalHwnd, SendPostedEventsTimerId,
223 USER_TIMER_MINIMUM, NULL);
282 HWND wnd = CreateWindow(ctx->className,
292 qErrnoWarning(
"CreateWindow() for QEventDispatcherWin32 internal window failed");
296 SetWindowLongPtr(wnd, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(eventDispatcher));
303 qint64 interval = t->interval;
304 ULONG tolerance = TIMERV_DEFAULT_COALESCING;
305 switch (t->timerType) {
306 case Qt::PreciseTimer:
311 case Qt::CoarseTimer:
316 if (interval >= 20000) {
317 t->timerType = Qt::VeryCoarseTimer;
318 }
else if (interval <= 20) {
320 t->timerType = Qt::PreciseTimer;
323 tolerance = interval / 20;
327 case Qt::VeryCoarseTimer:
334 interval = (interval + 500) / 1000 * 1000;
335 currentTime = currentTime / 1000 * 1000;
339 t->interval = interval;
340 t->timeout = currentTime + interval;
344void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
346 Q_ASSERT(internalHwnd);
348 Q_Q(QEventDispatcherWin32);
351 ULONG tolerance = calculateNextTimeout(t, qt_msectime());
352 uint interval = q26::saturate_cast<uint>(t->interval);
353 if (interval != t->interval) {
355 interval = q26::saturate_cast<uint>(t->interval / 2 + 1);
356 t->usesExtendedInterval =
true;
357 t->isSecondTimeout =
false;
359 if (interval == 0u) {
361 QCoreApplication::postEvent(q,
new QZeroTimerEvent(t->timerId));
363 }
else if (tolerance == TIMERV_DEFAULT_COALESCING) {
366 t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc,
DWORD_PTR(t),
373 ok = SetCoalescableTimer(internalHwnd, t->timerId, interval,
nullptr, tolerance);
376 ok = SetTimer(internalHwnd, t->timerId, interval,
nullptr);
379 qErrnoWarning(
"QEventDispatcherWin32::registerTimer: Failed to create a timer");
382void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
384 if (t->interval == 0) {
385 QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
386 }
else if (t->fastTimerId != 0) {
387 timeKillEvent(t->fastTimerId);
388 QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
390 KillTimer(internalHwnd, t->timerId);
393 if (!t->inTimerEvent)
397void QEventDispatcherWin32Private::sendTimerEvent(
int timerId)
399 WinTimerInfo *t = timerDict.value(timerId);
400 if (t && !t->inTimerEvent) {
401 if (t->usesExtendedInterval && !t->isSecondTimeout) {
403 t->isSecondTimeout =
true;
408 t->inTimerEvent =
true;
411 calculateNextTimeout(t, qt_msectime());
413 QTimerEvent e(t->timerId);
414 QCoreApplication::sendEvent(t->obj, &e);
417 if (t->timerId == -1) {
420 t->isSecondTimeout =
false;
421 t->inTimerEvent =
false;
445QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
446 : QAbstractEventDispatcherV2(dd, parent)
448 Q_D(QEventDispatcherWin32);
450 d->internalHwnd = qt_create_internal_window(
this);
473bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
475 Q_D(QEventDispatcherWin32);
478 const bool wasInterrupted = d->interrupt.fetchAndStoreRelaxed(
false);
488 auto threadData = d->threadData.loadRelaxed();
492 QVarLengthArray<MSG> processedTimers;
493 while (!d->interrupt.loadRelaxed()) {
496 if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
498 msg = d->queuedUserInputEvents.takeFirst();
499 }
else if (!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
501 msg = d->queuedSocketEvents.takeFirst();
502 }
else if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
503 if (flags.testFlag(QEventLoop::ExcludeUserInputEvents)
504 && isUserInputMessage(msg.message)) {
506 d->queuedUserInputEvents.append(msg);
509 if ((flags & QEventLoop::ExcludeSocketNotifiers)
510 && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
512 d->queuedSocketEvents.append(msg);
515 }
else if (MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, MWMO_ALERTABLE)
524 if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
525 d->startPostedEventsTimer();
530 if (msg.message == WM_TIMER) {
532 if (d->internalHwnd == msg.hwnd && msg.wParam == d->sendPostedEventsTimerId)
537 for (
int i = 0; !found && i < processedTimers.count(); ++i) {
538 const MSG processed = processedTimers.constData()[i];
539 found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
543 processedTimers.append(msg);
544 }
else if (msg.message == WM_QUIT) {
545 if (QCoreApplication::instance())
546 QCoreApplication::instance()->quit();
550 if (!filterNativeEvent(QByteArrayLiteral(
"windows_generic_MSG"), &msg, 0)) {
551 TranslateMessage(&msg);
552 DispatchMessage(&msg);
559 && !d->interrupt.loadRelaxed()
560 && flags.testFlag(QEventLoop::WaitForMoreEvents)
561 && threadData->canWaitLocked());
564 MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
572void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
575 qintptr sockfd = notifier->socket();
576 int type = notifier->type();
579 qWarning(
"QEventDispatcherWin32::registerSocketNotifier: invalid socket identifier");
582 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
583 qWarning(
"QEventDispatcherWin32: socket notifiers cannot be enabled from another thread");
588 Q_D(QEventDispatcherWin32);
589 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
590 QSNDict *dict = sn_vec[type];
592 if (QCoreApplication::closingDown())
595 if (dict->contains(sockfd)) {
596 const char *t[] = {
"Read",
"Write",
"Exception" };
598 qWarning(
"QSocketNotifier: Multiple socket notifiers for "
599 "same socket %" PRIdQINTPTR
" and type %s", sockfd, t[type]);
602 QSockNot *sn =
new QSockNot;
605 dict->insert(sn->fd, sn);
608 if (d->sn_read.contains(sockfd))
609 event |= FD_READ | FD_CLOSE | FD_ACCEPT;
610 if (d->sn_write.contains(sockfd))
611 event |= FD_WRITE | FD_CONNECT;
612 if (d->sn_except.contains(sockfd))
615 QSFDict::iterator it = d->active_fd.find(sockfd);
616 if (it != d->active_fd.end()) {
617 QSockFd &sd = it.value();
619 d->doWsaAsyncSelect(sockfd, 0);
632 d->active_fd.insert(sockfd, QSockFd(event, FD_READ | FD_CLOSE | FD_ACCEPT | FD_WRITE
633 | FD_CONNECT | FD_OOB));
636 d->postActivateSocketNotifiers();
656void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier)
658 Q_D(QEventDispatcherWin32);
659 int type = notifier->type();
660 qintptr sockfd = notifier->socket();
661 Q_ASSERT(sockfd >= 0);
663 QSFDict::iterator it = d->active_fd.find(sockfd);
664 if (it != d->active_fd.end()) {
665 QSockFd &sd = it.value();
667 d->doWsaAsyncSelect(sockfd, 0);
668 const long event[3] = { FD_READ | FD_CLOSE | FD_ACCEPT, FD_WRITE | FD_CONNECT, FD_OOB };
669 sd.event ^= event[type];
671 d->active_fd.erase(it);
672 }
else if (sd.selected) {
674 d->postActivateSocketNotifiers();
678 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
679 QSNDict *dict = sn_vec[type];
680 QSockNot *sn = dict->value(sockfd);
684 dict->remove(sockfd);
688void QEventDispatcherWin32::registerTimer(Qt::TimerId timerId, Duration interval,
689 Qt::TimerType timerType, QObject *object)
692 if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !object) {
693 qWarning(
"QEventDispatcherWin32::registerTimer: invalid arguments");
696 if (object->thread() != thread() || thread() != QThread::currentThread()) {
697 qWarning(
"QEventDispatcherWin32::registerTimer: timers cannot be started from another thread");
702 Q_D(QEventDispatcherWin32);
709 using namespace std::chrono;
711 WinTimerInfo *t =
new WinTimerInfo;
712 t->dispatcher =
this;
713 t->timerId = qToUnderlying(timerId);
715 t->interval = ceil<milliseconds>(interval).count();
716 t->timerType = timerType;
718 t->inTimerEvent =
false;
720 t->usesExtendedInterval =
false;
721 t->isSecondTimeout =
false;
725 d->timerDict.insert(t->timerId, t);
728bool QEventDispatcherWin32::unregisterTimer(Qt::TimerId timerId)
731 if (qToUnderlying(timerId) < 1) {
732 qWarning(
"QEventDispatcherWin32::unregisterTimer: invalid argument");
735 if (thread() != QThread::currentThread()) {
736 qWarning(
"QEventDispatcherWin32::unregisterTimer: timers cannot be stopped from another thread");
741 Q_D(QEventDispatcherWin32);
743 WinTimerInfo *t = d->timerDict.take(qToUnderlying(timerId));
747 d->unregisterTimer(t);
751bool QEventDispatcherWin32::unregisterTimers(QObject *object)
755 qWarning(
"QEventDispatcherWin32::unregisterTimers: invalid argument");
758 if (object->thread() != thread() || thread() != QThread::currentThread()) {
759 qWarning(
"QEventDispatcherWin32::unregisterTimers: timers cannot be stopped from another thread");
764 Q_D(QEventDispatcherWin32);
765 if (d->timerDict.isEmpty())
768 auto it = d->timerDict.begin();
769 while (it != d->timerDict.end()) {
770 WinTimerInfo *t = it.value();
772 if (t->obj == object) {
773 it = d->timerDict.erase(it);
774 d->unregisterTimer(t);
805QEventDispatcherWin32::Duration QEventDispatcherWin32::remainingTime(Qt::TimerId timerId)
const
808 if (qToUnderlying(timerId) < 1) {
809 qWarning(
"QEventDispatcherWin32::remainingTime: invalid argument");
810 return Duration::min();
814 Q_D(
const QEventDispatcherWin32);
816 WinTimerInfo *t = d->timerDict.value(qToUnderlying(timerId));
819 using namespace std::chrono;
820 using namespace std::chrono_literals;
821 const auto currentTimeMs = duration_cast<milliseconds>(steady_clock::now().time_since_epoch());
822 const auto timeoutMs = t->timeout * 1ms;
823 return timeoutMs > currentTimeMs ? milliseconds{timeoutMs - currentTimeMs} : 0ms;
827 qWarning(
"QEventDispatcherWin32::remainingTime: timer id %d not found", qToUnderlying(timerId));
830 return Duration::min();
833void QEventDispatcherWin32::wakeUp()
835 Q_D(QEventDispatcherWin32);
836 if (d->wakeUps.testAndSetRelaxed(0, 1)) {
838 if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0))
839 qErrnoWarning(
"QEventDispatcherWin32::wakeUp: Failed to post a message");
853void QEventDispatcherWin32::closingDown()
855 Q_D(QEventDispatcherWin32);
858 while (!d->sn_read.isEmpty())
859 doUnregisterSocketNotifier((*(d->sn_read.begin()))->obj);
860 while (!d->sn_write.isEmpty())
861 doUnregisterSocketNotifier((*(d->sn_write.begin()))->obj);
862 while (!d->sn_except.isEmpty())
863 doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj);
864 Q_ASSERT(d->active_fd.isEmpty());
867 for (WinTimerInfo *t : std::as_const(d->timerDict))
868 d->unregisterTimer(t);
869 d->timerDict.clear();
871 d->closingDown =
true;
873 if (d->sendPostedEventsTimerId != 0)
874 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
875 d->sendPostedEventsTimerId = 0;
878bool QEventDispatcherWin32::event(QEvent *e)
880 Q_D(QEventDispatcherWin32);
882 case QEvent::ZeroTimerEvent: {
883 QZeroTimerEvent *zte =
static_cast<QZeroTimerEvent*>(e);
884 WinTimerInfo *t = d->timerDict.value(zte->timerId());
886 t->inTimerEvent =
true;
888 QTimerEvent te(zte->timerId());
889 QCoreApplication::sendEvent(t->obj, &te);
892 if (t->timerId == -1) {
895 if (t->interval == 0 && t->inTimerEvent) {
897 QCoreApplication::postEvent(
this,
new QZeroTimerEvent(zte->timerId()));
900 t->inTimerEvent =
false;
906 d->sendTimerEvent(
static_cast<
const QTimerEvent*>(e)->timerId());
911 return QAbstractEventDispatcher::event(e);
914void QEventDispatcherWin32::sendPostedEvents()
916 Q_D(QEventDispatcherWin32);
918 if (d->sendPostedEventsTimerId != 0)
919 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
920 d->sendPostedEventsTimerId = 0;
923 d->wakeUps.storeRelaxed(0);
925 QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData.loadRelaxed());