217void QEventDispatcherWin32Private::startPostedEventsTimer()
220 wakeUps.storeRelaxed(0);
221 if (sendPostedEventsTimerId == 0) {
223 sendPostedEventsTimerId = SetTimer(internalHwnd, SendPostedEventsTimerId,
224 USER_TIMER_MINIMUM, NULL);
304 qint64 interval = t->interval;
305 ULONG tolerance = TIMERV_DEFAULT_COALESCING;
306 switch (t->timerType) {
307 case Qt::PreciseTimer:
312 case Qt::CoarseTimer:
317 if (interval >= 20000) {
318 t->timerType = Qt::VeryCoarseTimer;
319 }
else if (interval <= 20) {
321 t->timerType = Qt::PreciseTimer;
324 tolerance = interval / 20;
328 case Qt::VeryCoarseTimer:
335 interval = (interval + 500) / 1000 * 1000;
336 currentTime = currentTime / 1000 * 1000;
340 t->interval = interval;
341 t->timeout = currentTime + interval;
345void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
347 Q_ASSERT(internalHwnd);
349 Q_Q(QEventDispatcherWin32);
352 ULONG tolerance = calculateNextTimeout(t, qt_msectime());
353 uint interval = q26::saturate_cast<uint>(t->interval);
354 if (interval != t->interval) {
356 interval = q26::saturate_cast<uint>(t->interval / 2 + 1);
357 t->usesExtendedInterval =
true;
358 t->isSecondTimeout =
false;
360 if (interval == 0u) {
362 QCoreApplication::postEvent(q,
new QZeroTimerEvent(t->timerId));
364 }
else if (tolerance == TIMERV_DEFAULT_COALESCING) {
367 t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc,
DWORD_PTR(t),
374 ok = SetCoalescableTimer(internalHwnd, t->timerId, interval,
nullptr, tolerance);
377 ok = SetTimer(internalHwnd, t->timerId, interval,
nullptr);
380 qErrnoWarning(
"QEventDispatcherWin32::registerTimer: Failed to create a timer");
383void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
385 if (t->interval == 0) {
386 QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
387 }
else if (t->fastTimerId != 0) {
388 timeKillEvent(t->fastTimerId);
389 QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
391 KillTimer(internalHwnd, t->timerId);
394 if (!t->inTimerEvent)
398void QEventDispatcherWin32Private::sendTimerEvent(
int timerId)
400 WinTimerInfo *t = timerDict.value(timerId);
401 if (t && !t->inTimerEvent) {
402 if (t->usesExtendedInterval && !t->isSecondTimeout) {
404 t->isSecondTimeout =
true;
409 t->inTimerEvent =
true;
412 calculateNextTimeout(t, qt_msectime());
414 QTimerEvent e(t->timerId);
415 QCoreApplication::sendEvent(t->obj, &e);
418 if (t->timerId == -1) {
421 t->isSecondTimeout =
false;
422 t->inTimerEvent =
false;
446QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
447 : QAbstractEventDispatcherV2(dd, parent)
449 Q_D(QEventDispatcherWin32);
451 d->internalHwnd = qt_create_internal_window(
this);
474bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
476 Q_D(QEventDispatcherWin32);
479 const bool wasInterrupted = d->interrupt.fetchAndStoreRelaxed(
false);
489 auto threadData = d->threadData.loadRelaxed();
493 QVarLengthArray<MSG> processedTimers;
494 while (!d->interrupt.loadRelaxed()) {
497 if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
499 msg = d->queuedUserInputEvents.takeFirst();
500 }
else if (!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
502 msg = d->queuedSocketEvents.takeFirst();
503 }
else if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
504 if (flags.testFlag(QEventLoop::ExcludeUserInputEvents)
505 && isUserInputMessage(msg.message)) {
507 d->queuedUserInputEvents.append(msg);
510 if ((flags & QEventLoop::ExcludeSocketNotifiers)
511 && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
513 d->queuedSocketEvents.append(msg);
516 }
else if (MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, MWMO_ALERTABLE)
525 if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
526 d->startPostedEventsTimer();
531 if (msg.message == WM_TIMER) {
533 if (d->internalHwnd == msg.hwnd && msg.wParam == d->sendPostedEventsTimerId)
538 for (
int i = 0; !found && i < processedTimers.count(); ++i) {
539 const MSG processed = processedTimers.constData()[i];
540 found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
544 processedTimers.append(msg);
545 }
else if (msg.message == WM_QUIT) {
546 if (QCoreApplication::instance())
547 QCoreApplication::instance()->quit();
551 if (!filterNativeEvent(QByteArrayLiteral(
"windows_generic_MSG"), &msg, 0)) {
552 TranslateMessage(&msg);
553 DispatchMessage(&msg);
560 && !d->interrupt.loadRelaxed()
561 && flags.testFlag(QEventLoop::WaitForMoreEvents)
562 && threadData->canWaitLocked());
565 MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
573void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
576 qintptr sockfd = notifier->socket();
577 int type = notifier->type();
580 qWarning(
"QEventDispatcherWin32::registerSocketNotifier: invalid socket identifier");
583 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
584 qWarning(
"QEventDispatcherWin32: socket notifiers cannot be enabled from another thread");
589 Q_D(QEventDispatcherWin32);
590 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
591 QSNDict *dict = sn_vec[type];
593 if (QCoreApplication::closingDown())
596 if (dict->contains(sockfd)) {
597 const char *t[] = {
"Read",
"Write",
"Exception" };
599 qWarning(
"QSocketNotifier: Multiple socket notifiers for "
600 "same socket %" PRIdQINTPTR
" and type %s", sockfd, t[type]);
603 QSockNot *sn =
new QSockNot;
606 dict->insert(sn->fd, sn);
609 if (d->sn_read.contains(sockfd))
610 event |= FD_READ | FD_CLOSE | FD_ACCEPT;
611 if (d->sn_write.contains(sockfd))
612 event |= FD_WRITE | FD_CONNECT;
613 if (d->sn_except.contains(sockfd))
616 QSFDict::iterator it = d->active_fd.find(sockfd);
617 if (it != d->active_fd.end()) {
618 QSockFd &sd = it.value();
620 d->doWsaAsyncSelect(sockfd, 0);
633 d->active_fd.insert(sockfd, QSockFd(event, FD_READ | FD_CLOSE | FD_ACCEPT | FD_WRITE
634 | FD_CONNECT | FD_OOB));
637 d->postActivateSocketNotifiers();
657void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier)
659 Q_D(QEventDispatcherWin32);
660 int type = notifier->type();
661 qintptr sockfd = notifier->socket();
662 Q_ASSERT(sockfd >= 0);
664 QSFDict::iterator it = d->active_fd.find(sockfd);
665 if (it != d->active_fd.end()) {
666 QSockFd &sd = it.value();
668 d->doWsaAsyncSelect(sockfd, 0);
669 const long event[3] = { FD_READ | FD_CLOSE | FD_ACCEPT, FD_WRITE | FD_CONNECT, FD_OOB };
670 sd.event ^= event[type];
672 d->active_fd.erase(it);
673 }
else if (sd.selected) {
675 d->postActivateSocketNotifiers();
679 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
680 QSNDict *dict = sn_vec[type];
681 QSockNot *sn = dict->value(sockfd);
685 dict->remove(sockfd);
689void QEventDispatcherWin32::registerTimer(Qt::TimerId timerId, Duration interval,
690 Qt::TimerType timerType, QObject *object)
693 if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !object) {
694 qWarning(
"QEventDispatcherWin32::registerTimer: invalid arguments");
697 if (object->thread() != thread() || thread() != QThread::currentThread()) {
698 qWarning(
"QEventDispatcherWin32::registerTimer: timers cannot be started from another thread");
703 Q_D(QEventDispatcherWin32);
710 using namespace std::chrono;
712 WinTimerInfo *t =
new WinTimerInfo;
713 t->dispatcher =
this;
714 t->timerId = qToUnderlying(timerId);
716 t->interval = ceil<milliseconds>(interval).count();
717 t->timerType = timerType;
719 t->inTimerEvent =
false;
721 t->usesExtendedInterval =
false;
722 t->isSecondTimeout =
false;
726 d->timerDict.insert(t->timerId, t);
729bool QEventDispatcherWin32::unregisterTimer(Qt::TimerId timerId)
732 if (qToUnderlying(timerId) < 1) {
733 qWarning(
"QEventDispatcherWin32::unregisterTimer: invalid argument");
736 if (thread() != QThread::currentThread()) {
737 qWarning(
"QEventDispatcherWin32::unregisterTimer: timers cannot be stopped from another thread");
742 Q_D(QEventDispatcherWin32);
744 WinTimerInfo *t = d->timerDict.take(qToUnderlying(timerId));
748 d->unregisterTimer(t);
752bool QEventDispatcherWin32::unregisterTimers(QObject *object)
756 qWarning(
"QEventDispatcherWin32::unregisterTimers: invalid argument");
759 if (object->thread() != thread() || thread() != QThread::currentThread()) {
760 qWarning(
"QEventDispatcherWin32::unregisterTimers: timers cannot be stopped from another thread");
765 Q_D(QEventDispatcherWin32);
766 if (d->timerDict.isEmpty())
769 auto it = d->timerDict.begin();
770 while (it != d->timerDict.end()) {
771 WinTimerInfo *t = it.value();
773 if (t->obj == object) {
774 it = d->timerDict.erase(it);
775 d->unregisterTimer(t);
806QEventDispatcherWin32::Duration QEventDispatcherWin32::remainingTime(Qt::TimerId timerId)
const
809 if (qToUnderlying(timerId) < 1) {
810 qWarning(
"QEventDispatcherWin32::remainingTime: invalid argument");
811 return Duration::min();
815 Q_D(
const QEventDispatcherWin32);
817 WinTimerInfo *t = d->timerDict.value(qToUnderlying(timerId));
820 using namespace std::chrono;
821 using namespace std::chrono_literals;
822 const auto currentTimeMs = duration_cast<milliseconds>(steady_clock::now().time_since_epoch());
823 const auto timeoutMs = t->timeout * 1ms;
824 return timeoutMs > currentTimeMs ? milliseconds{timeoutMs - currentTimeMs} : 0ms;
828 qWarning(
"QEventDispatcherWin32::remainingTime: timer id %d not found", qToUnderlying(timerId));
831 return Duration::min();
834void QEventDispatcherWin32::wakeUp()
836 Q_D(QEventDispatcherWin32);
837 if (d->wakeUps.testAndSetRelaxed(0, 1)) {
839 if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0))
840 qErrnoWarning(
"QEventDispatcherWin32::wakeUp: Failed to post a message");
854void QEventDispatcherWin32::closingDown()
856 Q_D(QEventDispatcherWin32);
859 while (!d->sn_read.isEmpty())
860 doUnregisterSocketNotifier((*(d->sn_read.begin()))->obj);
861 while (!d->sn_write.isEmpty())
862 doUnregisterSocketNotifier((*(d->sn_write.begin()))->obj);
863 while (!d->sn_except.isEmpty())
864 doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj);
865 Q_ASSERT(d->active_fd.isEmpty());
868 for (WinTimerInfo *t : std::as_const(d->timerDict))
869 d->unregisterTimer(t);
870 d->timerDict.clear();
872 d->closingDown =
true;
874 if (d->sendPostedEventsTimerId != 0)
875 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
876 d->sendPostedEventsTimerId = 0;
879bool QEventDispatcherWin32::event(QEvent *e)
881 Q_D(QEventDispatcherWin32);
883 case QEvent::ZeroTimerEvent: {
884 QZeroTimerEvent *zte =
static_cast<QZeroTimerEvent*>(e);
885 WinTimerInfo *t = d->timerDict.value(zte->timerId());
887 t->inTimerEvent =
true;
889 QTimerEvent te(zte->timerId());
890 QCoreApplication::sendEvent(t->obj, &te);
893 if (t->timerId == -1) {
896 if (t->interval == 0 && t->inTimerEvent) {
898 QCoreApplication::postEvent(
this,
new QZeroTimerEvent(zte->timerId()));
901 t->inTimerEvent =
false;
907 d->sendTimerEvent(
static_cast<
const QTimerEvent*>(e)->timerId());
912 return QAbstractEventDispatcher::event(e);
915void QEventDispatcherWin32::sendPostedEvents()
917 Q_D(QEventDispatcherWin32);
919 if (d->sendPostedEventsTimerId != 0)
920 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
921 d->sendPostedEventsTimerId = 0;
924 d->wakeUps.storeRelaxed(0);
926 QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData.loadRelaxed());