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::saturating_cast<uint>(t->interval);
354 if (interval != t->interval) {
356 interval = q26::saturating_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),
372 qWarning(
"QEventDispatcherWin32Private::registerTimer: Failed "
373 "to create a precise timer with interval %u ms, "
374 "downgrading to a coarse one...", interval);
379 ok = SetCoalescableTimer(internalHwnd, t->timerId, interval,
nullptr, tolerance);
382 ok = SetTimer(internalHwnd, t->timerId, interval,
nullptr);
385 qErrnoWarning(
"QEventDispatcherWin32::registerTimer: Failed to create a timer");
388void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
390 if (t->interval == 0) {
391 QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
392 }
else if (t->fastTimerId != 0) {
393 timeKillEvent(t->fastTimerId);
394 QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
396 KillTimer(internalHwnd, t->timerId);
399 if (!t->inTimerEvent)
403void QEventDispatcherWin32Private::sendTimerEvent(
int timerId)
405 WinTimerInfo *t = timerDict.value(timerId);
406 if (t && !t->inTimerEvent) {
407 if (t->usesExtendedInterval && !t->isSecondTimeout) {
409 t->isSecondTimeout =
true;
414 t->inTimerEvent =
true;
417 calculateNextTimeout(t, qt_msectime());
419 QTimerEvent e(t->timerId);
420 QCoreApplication::sendEvent(t->obj, &e);
423 if (t->timerId == -1) {
426 t->isSecondTimeout =
false;
427 t->inTimerEvent =
false;
451QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
452 : QAbstractEventDispatcherV2(dd, parent)
454 Q_D(QEventDispatcherWin32);
456 d->internalHwnd = qt_create_internal_window(
this);
479bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
481 Q_D(QEventDispatcherWin32);
484 const bool wasInterrupted = d->interrupt.fetchAndStoreRelaxed(
false);
494 auto threadData = d->threadData.loadRelaxed();
498 QVarLengthArray<MSG> processedTimers;
499 while (!d->interrupt.loadRelaxed()) {
502 if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
504 msg = d->queuedUserInputEvents.takeFirst();
505 }
else if (!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
507 msg = d->queuedSocketEvents.takeFirst();
508 }
else if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
509 if (flags.testFlag(QEventLoop::ExcludeUserInputEvents)
510 && isUserInputMessage(msg.message)) {
512 d->queuedUserInputEvents.append(msg);
515 if ((flags & QEventLoop::ExcludeSocketNotifiers)
516 && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
518 d->queuedSocketEvents.append(msg);
521 }
else if (MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, MWMO_ALERTABLE)
530 if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
531 d->startPostedEventsTimer();
536 if (msg.message == WM_TIMER) {
538 if (d->internalHwnd == msg.hwnd && msg.wParam == d->sendPostedEventsTimerId)
543 for (
int i = 0; !found && i < processedTimers.count(); ++i) {
544 const MSG processed = processedTimers.constData()[i];
545 found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
549 processedTimers.append(msg);
550 }
else if (msg.message == WM_QUIT) {
551 if (QCoreApplication::instance())
552 QCoreApplication::instance()->quit();
556 if (!filterNativeEvent(QByteArrayLiteral(
"windows_generic_MSG"), &msg, 0)) {
557 TranslateMessage(&msg);
558 DispatchMessage(&msg);
565 && !d->interrupt.loadRelaxed()
566 && flags.testFlag(QEventLoop::WaitForMoreEvents)
567 && threadData->canWaitLocked());
570 MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
578void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
581 qintptr sockfd = notifier->socket();
582 int type = notifier->type();
585 qWarning(
"QEventDispatcherWin32::registerSocketNotifier: invalid socket identifier");
588 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
589 qWarning(
"QEventDispatcherWin32: socket notifiers cannot be enabled from another thread");
594 Q_D(QEventDispatcherWin32);
595 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
596 QSNDict *dict = sn_vec[type];
598 if (QCoreApplication::closingDown())
601 if (dict->contains(sockfd)) {
602 const char *t[] = {
"Read",
"Write",
"Exception" };
604 qWarning(
"QSocketNotifier: Multiple socket notifiers for "
605 "same socket %" PRIdQINTPTR
" and type %s", sockfd, t[type]);
608 QSockNot *sn =
new QSockNot;
611 dict->insert(sn->fd, sn);
614 if (d->sn_read.contains(sockfd))
615 event |= FD_READ | FD_CLOSE | FD_ACCEPT;
616 if (d->sn_write.contains(sockfd))
617 event |= FD_WRITE | FD_CONNECT;
618 if (d->sn_except.contains(sockfd))
621 QSFDict::iterator it = d->active_fd.find(sockfd);
622 if (it != d->active_fd.end()) {
623 QSockFd &sd = it.value();
625 d->doWsaAsyncSelect(sockfd, 0);
638 d->active_fd.insert(sockfd, QSockFd(event, FD_READ | FD_CLOSE | FD_ACCEPT | FD_WRITE
639 | FD_CONNECT | FD_OOB));
642 d->postActivateSocketNotifiers();
662void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier)
664 Q_D(QEventDispatcherWin32);
665 int type = notifier->type();
666 qintptr sockfd = notifier->socket();
667 Q_ASSERT(sockfd >= 0);
669 QSFDict::iterator it = d->active_fd.find(sockfd);
670 if (it != d->active_fd.end()) {
671 QSockFd &sd = it.value();
673 d->doWsaAsyncSelect(sockfd, 0);
674 const long event[3] = { FD_READ | FD_CLOSE | FD_ACCEPT, FD_WRITE | FD_CONNECT, FD_OOB };
675 sd.event ^= event[type];
677 d->active_fd.erase(it);
678 }
else if (sd.selected) {
680 d->postActivateSocketNotifiers();
684 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
685 QSNDict *dict = sn_vec[type];
686 QSockNot *sn = dict->value(sockfd);
690 dict->remove(sockfd);
694void QEventDispatcherWin32::registerTimer(Qt::TimerId timerId, Duration interval,
695 Qt::TimerType timerType, QObject *object)
698 if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !object) {
699 qWarning(
"QEventDispatcherWin32::registerTimer: invalid arguments");
702 if (object->thread() != thread() || thread() != QThread::currentThread()) {
703 qWarning(
"QEventDispatcherWin32::registerTimer: timers cannot be started from another thread");
708 Q_D(QEventDispatcherWin32);
715 using namespace std::chrono;
717 WinTimerInfo *t =
new WinTimerInfo;
718 t->dispatcher =
this;
719 t->timerId = qToUnderlying(timerId);
721 t->interval = ceil<milliseconds>(interval).count();
722 t->timerType = timerType;
724 t->inTimerEvent =
false;
726 t->usesExtendedInterval =
false;
727 t->isSecondTimeout =
false;
731 d->timerDict.insert(t->timerId, t);
734bool QEventDispatcherWin32::unregisterTimer(Qt::TimerId timerId)
737 if (qToUnderlying(timerId) < 1) {
738 qWarning(
"QEventDispatcherWin32::unregisterTimer: invalid argument");
741 if (thread() != QThread::currentThread()) {
742 qWarning(
"QEventDispatcherWin32::unregisterTimer: timers cannot be stopped from another thread");
747 Q_D(QEventDispatcherWin32);
749 WinTimerInfo *t = d->timerDict.take(qToUnderlying(timerId));
753 d->unregisterTimer(t);
757bool QEventDispatcherWin32::unregisterTimers(QObject *object)
761 qWarning(
"QEventDispatcherWin32::unregisterTimers: invalid argument");
764 if (object->thread() != thread() || thread() != QThread::currentThread()) {
765 qWarning(
"QEventDispatcherWin32::unregisterTimers: timers cannot be stopped from another thread");
770 Q_D(QEventDispatcherWin32);
771 if (d->timerDict.isEmpty())
774 auto it = d->timerDict.begin();
775 while (it != d->timerDict.end()) {
776 WinTimerInfo *t = it.value();
778 if (t->obj == object) {
779 it = d->timerDict.erase(it);
780 d->unregisterTimer(t);
811QEventDispatcherWin32::Duration QEventDispatcherWin32::remainingTime(Qt::TimerId timerId)
const
814 if (qToUnderlying(timerId) < 1) {
815 qWarning(
"QEventDispatcherWin32::remainingTime: invalid argument");
816 return Duration::min();
820 Q_D(
const QEventDispatcherWin32);
822 WinTimerInfo *t = d->timerDict.value(qToUnderlying(timerId));
825 using namespace std::chrono;
826 using namespace std::chrono_literals;
827 const auto currentTimeMs = duration_cast<milliseconds>(steady_clock::now().time_since_epoch());
828 const auto timeoutMs = t->timeout * 1ms;
829 return timeoutMs > currentTimeMs ? milliseconds{timeoutMs - currentTimeMs} : 0ms;
833 qWarning(
"QEventDispatcherWin32::remainingTime: timer id %d not found", qToUnderlying(timerId));
836 return Duration::min();
839void QEventDispatcherWin32::wakeUp()
841 Q_D(QEventDispatcherWin32);
842 if (d->wakeUps.testAndSetRelaxed(0, 1)) {
844 if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0))
845 qErrnoWarning(
"QEventDispatcherWin32::wakeUp: Failed to post a message");
859void QEventDispatcherWin32::closingDown()
861 Q_D(QEventDispatcherWin32);
864 while (!d->sn_read.isEmpty())
865 doUnregisterSocketNotifier((*(d->sn_read.begin()))->obj);
866 while (!d->sn_write.isEmpty())
867 doUnregisterSocketNotifier((*(d->sn_write.begin()))->obj);
868 while (!d->sn_except.isEmpty())
869 doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj);
870 Q_ASSERT(d->active_fd.isEmpty());
873 for (WinTimerInfo *t : std::as_const(d->timerDict))
874 d->unregisterTimer(t);
875 d->timerDict.clear();
877 d->closingDown =
true;
879 if (d->sendPostedEventsTimerId != 0)
880 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
881 d->sendPostedEventsTimerId = 0;
884bool QEventDispatcherWin32::event(QEvent *e)
886 Q_D(QEventDispatcherWin32);
888 case QEvent::ZeroTimerEvent: {
889 QZeroTimerEvent *zte =
static_cast<QZeroTimerEvent*>(e);
890 WinTimerInfo *t = d->timerDict.value(zte->timerId());
892 t->inTimerEvent =
true;
894 QTimerEvent te(zte->timerId());
895 QCoreApplication::sendEvent(t->obj, &te);
898 if (t->timerId == -1) {
901 if (t->interval == 0 && t->inTimerEvent) {
903 QCoreApplication::postEvent(
this,
new QZeroTimerEvent(zte->timerId()));
906 t->inTimerEvent =
false;
912 d->sendTimerEvent(
static_cast<
const QTimerEvent*>(e)->timerId());
917 return QAbstractEventDispatcher::event(e);
920void QEventDispatcherWin32::sendPostedEvents()
922 Q_D(QEventDispatcherWin32);
924 if (d->sendPostedEventsTimerId != 0)
925 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
926 d->sendPostedEventsTimerId = 0;
929 d->wakeUps.storeRelaxed(0);
931 QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData.loadRelaxed());