Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qeventdispatcher_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
7
9#include <private/qsystemlibrary_p.h>
11#include "qset.h"
14
15#include "qelapsedtimer.h"
17#include <private/qthread_p.h>
18
19#include "q26numeric.h"
20
22
23#ifndef TIME_KILL_SYNCHRONOUS
24# define TIME_KILL_SYNCHRONOUS 0x0100
25#endif
26
27#ifndef QS_RAWINPUT
28# define QS_RAWINPUT 0x0400
29#endif
30
31#ifndef WM_TOUCH
32# define WM_TOUCH 0x0240
33#endif
34#ifndef QT_NO_GESTURES
35#ifndef WM_GESTURE
36# define WM_GESTURE 0x0119
37#endif
38#ifndef WM_GESTURENOTIFY
39# define WM_GESTURENOTIFY 0x011A
40#endif
41#endif // QT_NO_GESTURES
42
43enum {
47};
48
49enum {
51};
52
53class QEventDispatcherWin32Private;
54
55#if !defined(DWORD_PTR) && !defined(Q_OS_WIN64)
56#define DWORD_PTR DWORD
57#endif
58
59LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
60
62{
63 using namespace std::chrono;
64 auto t = duration_cast<milliseconds>(steady_clock::now().time_since_epoch());
65 return t.count();
66}
67
68QEventDispatcherWin32Private::QEventDispatcherWin32Private()
69 : interrupt(false), internalHwnd(0),
70 sendPostedEventsTimerId(0), wakeUps(0),
71 activateNotifiersPosted(false)
72{
73}
74
75QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
76{
77 if (internalHwnd)
78 DestroyWindow(internalHwnd);
79}
80
81// This function is called by a workerthread
82void WINAPI QT_WIN_CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/)
83{
84 if (!timerId) // sanity check
85 return;
86 auto t = reinterpret_cast<WinTimerInfo*>(user);
87 Q_ASSERT(t);
88 QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId));
89}
90
91LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
92{
93 if (message == WM_NCCREATE)
94 return true;
95
96 MSG msg;
97 msg.hwnd = hwnd;
98 msg.message = message;
99 msg.wParam = wp;
100 msg.lParam = lp;
101 QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
102 qintptr result;
103 if (!dispatcher) {
104 if (message == WM_TIMER)
105 KillTimer(hwnd, wp);
106 return 0;
107 }
108 if (dispatcher->filterNativeEvent(QByteArrayLiteral("windows_dispatcher_MSG"), &msg, &result))
109 return result;
110
111 auto q = reinterpret_cast<QEventDispatcherWin32 *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
112 QEventDispatcherWin32Private *d = nullptr;
113 if (q != nullptr)
114 d = q->d_func();
115
116 switch (message) {
117 case WM_QT_SOCKETNOTIFIER: {
118 // socket notifier message
119 int type = -1;
120 switch (WSAGETSELECTEVENT(lp)) {
121 case FD_READ:
122 case FD_ACCEPT:
123 type = 0;
124 break;
125 case FD_WRITE:
126 case FD_CONNECT:
127 type = 1;
128 break;
129 case FD_OOB:
130 type = 2;
131 break;
132 case FD_CLOSE:
133 type = 3;
134 break;
135 }
136 if (type >= 0) {
137 Q_ASSERT(d != nullptr);
138 QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read };
139 QSNDict *dict = sn_vec[type];
140
141 QSockNot *sn = dict ? dict->value(qintptr(wp)) : 0;
142 if (sn == nullptr) {
143 d->postActivateSocketNotifiers();
144 } else {
145 Q_ASSERT(d->active_fd.contains(sn->fd));
146 QSockFd &sd = d->active_fd[sn->fd];
147 if (sd.selected) {
148 Q_ASSERT(sd.mask == 0);
149 d->doWsaAsyncSelect(sn->fd, 0);
150 sd.selected = false;
151 }
152 d->postActivateSocketNotifiers();
153
154 // Ignore the message if a notification with the same type was
155 // received previously. Suppressed message is definitely spurious.
156 const long eventCode = WSAGETSELECTEVENT(lp);
157 if ((sd.mask & eventCode) != eventCode) {
158 sd.mask |= eventCode;
159 QEvent event(type < 3 ? QEvent::SockAct : QEvent::SockClose);
160 QCoreApplication::sendEvent(sn->obj, &event);
161 }
162 }
163 }
164 return 0;
165 }
166 case WM_QT_ACTIVATENOTIFIERS: {
167 Q_ASSERT(d != nullptr);
168
169 // Postpone activation if we have unhandled socket notifier messages
170 // in the queue. WM_QT_ACTIVATENOTIFIERS will be posted again as a result of
171 // event processing.
172 MSG msg;
173 if (!PeekMessage(&msg, d->internalHwnd,
174 WM_QT_SOCKETNOTIFIER, WM_QT_SOCKETNOTIFIER, PM_NOREMOVE)
175 && d->queuedSocketEvents.isEmpty()) {
176 // register all socket notifiers
177 for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end();
178 it != end; ++it) {
179 QSockFd &sd = it.value();
180 if (!sd.selected) {
181 d->doWsaAsyncSelect(it.key(), sd.event);
182 // allow any event to be accepted
183 sd.mask = 0;
184 sd.selected = true;
185 }
186 }
187 }
188 d->activateNotifiersPosted = false;
189 return 0;
190 }
191 case WM_TIMER:
192 Q_ASSERT(d != nullptr);
193
194 if (wp == d->sendPostedEventsTimerId)
195 q->sendPostedEvents();
196 else
197 d->sendTimerEvent(wp);
198 return 0;
199 case WM_QT_SENDPOSTEDEVENTS:
200 Q_ASSERT(d != nullptr);
201
202 // We send posted events manually, if the window procedure was invoked
203 // by the foreign event loop (e.g. from the native modal dialog).
204 // Skip sending, if the message queue is not empty.
205 // sendPostedEventsTimer will deliver posted events later.
206 static const UINT mask = QS_ALLEVENTS;
207 if (HIWORD(GetQueueStatus(mask)) == 0)
208 q->sendPostedEvents();
209 else
210 d->startPostedEventsTimer();
211 return 0;
212 } // switch (message)
213
214 return DefWindowProc(hwnd, message, wp, lp);
215}
216
217void QEventDispatcherWin32Private::startPostedEventsTimer()
218{
219 // we received WM_QT_SENDPOSTEDEVENTS, so allow posting it again
220 wakeUps.storeRelaxed(0);
221 if (sendPostedEventsTimerId == 0) {
222 // Start a timer to deliver posted events when the message queue is emptied.
223 sendPostedEventsTimerId = SetTimer(internalHwnd, SendPostedEventsTimerId,
224 USER_TIMER_MINIMUM, NULL);
225 }
226}
227
228// Provide class name and atom for the message window used by
229// QEventDispatcherWin32Private via Q_GLOBAL_STATIC shared between threads.
238
240 : atom(0), className(0)
241{
242 // make sure that multiple Qt's can coexist in the same process
243 const QString qClassName = QStringLiteral("QEventDispatcherWin32_Internal_Widget")
244 + QString::number(quintptr(qt_internal_proc));
245 className = new wchar_t[qClassName.size() + 1];
246 qClassName.toWCharArray(className);
247 className[qClassName.size()] = 0;
248
249 WNDCLASS wc;
250 wc.style = 0;
251 wc.lpfnWndProc = qt_internal_proc;
252 wc.cbClsExtra = 0;
253 wc.cbWndExtra = 0;
254 wc.hInstance = GetModuleHandle(0);
255 wc.hIcon = 0;
256 wc.hCursor = 0;
257 wc.hbrBackground = 0;
258 wc.lpszMenuName = NULL;
259 wc.lpszClassName = className;
260 atom = RegisterClass(&wc);
261 if (!atom) {
262 qErrnoWarning("%ls RegisterClass() failed", qUtf16Printable(qClassName));
263 delete [] className;
264 className = 0;
265 }
266}
267
269{
270 if (className) {
271 UnregisterClass(className, GetModuleHandle(0));
272 delete [] className;
273 }
274}
275
276Q_GLOBAL_STATIC(QWindowsMessageWindowClassContext, qWindowsMessageWindowClassContext)
277
278static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher)
279{
280 QWindowsMessageWindowClassContext *ctx = qWindowsMessageWindowClassContext();
281 if (!ctx->atom)
282 return 0;
283 HWND wnd = CreateWindow(ctx->className, // classname
284 ctx->className, // window name
285 0, // style
286 0, 0, 0, 0, // geometry
287 HWND_MESSAGE, // parent
288 0, // menu handle
289 GetModuleHandle(0), // application
290 0); // windows creation data.
291
292 if (!wnd) {
293 qErrnoWarning("CreateWindow() for QEventDispatcherWin32 internal window failed");
294 return 0;
295 }
296
297 SetWindowLongPtr(wnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(eventDispatcher));
298
299 return wnd;
300}
301
302static ULONG calculateNextTimeout(WinTimerInfo *t, quint64 currentTime)
303{
304 qint64 interval = t->interval;
305 ULONG tolerance = TIMERV_DEFAULT_COALESCING;
306 switch (t->timerType) {
307 case Qt::PreciseTimer:
308 // high precision timer is based on millisecond precision
309 // so no adjustment is necessary
310 break;
311
312 case Qt::CoarseTimer:
313 // this timer has up to 5% coarseness
314 // so our boundaries are 20 ms and 20 s
315 // below 20 ms, 5% inaccuracy is below 1 ms, so we convert to high precision
316 // above 20 s, 5% inaccuracy is above 1 s, so we convert to VeryCoarseTimer
317 if (interval >= 20000) {
318 t->timerType = Qt::VeryCoarseTimer;
319 } else if (interval <= 20) {
320 // no adjustment necessary
321 t->timerType = Qt::PreciseTimer;
322 break;
323 } else {
324 tolerance = interval / 20;
325 break;
326 }
327 Q_FALLTHROUGH();
328 case Qt::VeryCoarseTimer:
329 // the very coarse timer is based on full second precision,
330 // so we round to closest second (but never to zero)
331 tolerance = 1000;
332 if (interval < 1000)
333 interval = 1000;
334 else
335 interval = (interval + 500) / 1000 * 1000;
336 currentTime = currentTime / 1000 * 1000;
337 break;
338 }
339
340 t->interval = interval;
341 t->timeout = currentTime + interval;
342 return tolerance;
343}
344
345void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
346{
347 Q_ASSERT(internalHwnd);
348
349 Q_Q(QEventDispatcherWin32);
350
351 bool ok = false;
352 ULONG tolerance = calculateNextTimeout(t, qt_msectime());
353 uint interval = q26::saturating_cast<uint>(t->interval);
354 if (interval != t->interval) {
355 // Now we'll need to post the timer event at each second timeout.
356 interval = q26::saturating_cast<uint>(t->interval / 2 + 1);
357 t->usesExtendedInterval = true;
358 t->isSecondTimeout = false;
359 }
360 if (interval == 0u) {
361 // optimization for single-shot-zero-timer
362 QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
363 ok = true;
364 } else if (tolerance == TIMERV_DEFAULT_COALESCING) {
365 // 3/2016: Although MSDN states timeSetEvent() is deprecated, the function
366 // is still deemed to be the most reliable precision timer.
367 t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc, DWORD_PTR(t),
368 TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
369 ok = t->fastTimerId;
370
371 if (!ok)
372 qWarning("QEventDispatcherWin32Private::registerTimer: Failed "
373 "to create a precise timer with interval %u ms, "
374 "downgrading to a coarse one...", interval);
375 }
376
377 if (!ok) {
378 // user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
379 ok = SetCoalescableTimer(internalHwnd, t->timerId, interval, nullptr, tolerance);
380 }
381 if (!ok)
382 ok = SetTimer(internalHwnd, t->timerId, interval, nullptr);
383
384 if (!ok)
385 qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
386}
387
388void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
389{
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);
395 } else {
396 KillTimer(internalHwnd, t->timerId);
397 }
398 t->timerId = -1;
399 if (!t->inTimerEvent)
400 delete t;
401}
402
403void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
404{
405 WinTimerInfo *t = timerDict.value(timerId);
406 if (t && !t->inTimerEvent) {
407 if (t->usesExtendedInterval && !t->isSecondTimeout) {
408 // That's the case when the interval is larger than uint
409 t->isSecondTimeout = true;
410 return;
411 }
412
413 // send event, but don't allow it to recurse
414 t->inTimerEvent = true;
415
416 // recalculate next emission
417 calculateNextTimeout(t, qt_msectime());
418
419 QTimerEvent e(t->timerId);
420 QCoreApplication::sendEvent(t->obj, &e);
421
422 // timer could have been removed
423 if (t->timerId == -1) {
424 delete t;
425 } else {
426 t->isSecondTimeout = false;
427 t->inTimerEvent = false;
428 }
429 }
430}
431
432void QEventDispatcherWin32Private::doWsaAsyncSelect(qintptr socket, long event)
433{
434 Q_ASSERT(internalHwnd);
435 // BoundsChecker may emit a warning for WSAAsyncSelect when event == 0
436 // This is a BoundsChecker bug and not a Qt bug
437 WSAAsyncSelect(socket, internalHwnd, event ? int(WM_QT_SOCKETNOTIFIER) : 0, event);
438}
439
440void QEventDispatcherWin32Private::postActivateSocketNotifiers()
441{
442 if (!activateNotifiersPosted)
443 activateNotifiersPosted = PostMessage(internalHwnd, WM_QT_ACTIVATENOTIFIERS, 0, 0);
444}
445
446QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
447 : QEventDispatcherWin32(*new QEventDispatcherWin32Private, parent)
448{
449}
450
451QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
452 : QAbstractEventDispatcherV2(dd, parent)
453{
454 Q_D(QEventDispatcherWin32);
455
456 d->internalHwnd = qt_create_internal_window(this);
457}
458
459QEventDispatcherWin32::~QEventDispatcherWin32()
460{
461}
462
463static bool isUserInputMessage(UINT message)
464{
465 return (message >= WM_KEYFIRST && message <= WM_KEYLAST)
466 || (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST)
467 || message == WM_MOUSEWHEEL
468 || message == WM_MOUSEHWHEEL
469 || message == WM_TOUCH
470#ifndef QT_NO_GESTURES
471 || message == WM_GESTURE
472 || message == WM_GESTURENOTIFY
473#endif
474// Pointer input: Exclude WM_NCPOINTERUPDATE .. WM_POINTERROUTEDRELEASED
475 || (message >= 0x0241 && message <= 0x0253)
476 || message == WM_CLOSE;
477}
478
479bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
480{
481 Q_D(QEventDispatcherWin32);
482
483 // We don't know _when_ the interrupt occurred so we have to honor it.
484 const bool wasInterrupted = d->interrupt.fetchAndStoreRelaxed(false);
485 emit awake();
486
487 // To prevent livelocks, send posted events once per iteration.
488 // QCoreApplication::sendPostedEvents() takes care about recursions.
489 sendPostedEvents();
490
491 if (wasInterrupted)
492 return false;
493
494 auto threadData = d->threadData.loadRelaxed();
495 bool canWait;
496 bool retVal = false;
497 do {
498 QVarLengthArray<MSG> processedTimers;
499 while (!d->interrupt.loadRelaxed()) {
500 MSG msg;
501
502 if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
503 // process queued user input events
504 msg = d->queuedUserInputEvents.takeFirst();
505 } else if (!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
506 // process queued socket events
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)) {
511 // queue user input events for later processing
512 d->queuedUserInputEvents.append(msg);
513 continue;
514 }
515 if ((flags & QEventLoop::ExcludeSocketNotifiers)
516 && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
517 // queue socket events for later processing
518 d->queuedSocketEvents.append(msg);
519 continue;
520 }
521 } else if (MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, MWMO_ALERTABLE)
522 == WAIT_OBJECT_0) {
523 // a new message has arrived, process it
524 continue;
525 } else {
526 // nothing to do, so break
527 break;
528 }
529
530 if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
531 d->startPostedEventsTimer();
532 // Set result to 'true' because the message was sent by wakeUp().
533 retVal = true;
534 continue;
535 }
536 if (msg.message == WM_TIMER) {
537 // Skip timer event intended for use inside foreign loop.
538 if (d->internalHwnd == msg.hwnd && msg.wParam == d->sendPostedEventsTimerId)
539 continue;
540
541 // avoid live-lock by keeping track of the timers we've already sent
542 bool found = false;
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);
546 }
547 if (found)
548 continue;
549 processedTimers.append(msg);
550 } else if (msg.message == WM_QUIT) {
551 if (QCoreApplication::instance())
552 QCoreApplication::instance()->quit();
553 return false;
554 }
555
556 if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) {
557 TranslateMessage(&msg);
558 DispatchMessage(&msg);
559 }
560 retVal = true;
561 }
562
563 // wait for message
564 canWait = (!retVal
565 && !d->interrupt.loadRelaxed()
566 && flags.testFlag(QEventLoop::WaitForMoreEvents)
567 && threadData->canWaitLocked());
568 if (canWait) {
569 emit aboutToBlock();
570 MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
571 emit awake();
572 }
573 } while (canWait);
574
575 return retVal;
576}
577
578void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
579{
580 Q_ASSERT(notifier);
581 qintptr sockfd = notifier->socket();
582 int type = notifier->type();
583#ifndef QT_NO_DEBUG
584 if (sockfd < 0) {
585 qWarning("QEventDispatcherWin32::registerSocketNotifier: invalid socket identifier");
586 return;
587 }
588 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
589 qWarning("QEventDispatcherWin32: socket notifiers cannot be enabled from another thread");
590 return;
591 }
592#endif
593
594 Q_D(QEventDispatcherWin32);
595 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
596 QSNDict *dict = sn_vec[type];
597
598 if (QCoreApplication::closingDown()) // ### d->exitloop?
599 return; // after sn_cleanup, don't reinitialize.
600
601 if (dict->contains(sockfd)) {
602 const char *t[] = { "Read", "Write", "Exception" };
603 /* Variable "socket" below is a function pointer. */
604 qWarning("QSocketNotifier: Multiple socket notifiers for "
605 "same socket %" PRIdQINTPTR " and type %s", sockfd, t[type]);
606 }
607
608 QSockNot *sn = new QSockNot;
609 sn->obj = notifier;
610 sn->fd = sockfd;
611 dict->insert(sn->fd, sn);
612
613 long event = 0;
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))
619 event |= FD_OOB;
620
621 QSFDict::iterator it = d->active_fd.find(sockfd);
622 if (it != d->active_fd.end()) {
623 QSockFd &sd = it.value();
624 if (sd.selected) {
625 d->doWsaAsyncSelect(sockfd, 0);
626 sd.selected = false;
627 }
628 sd.event |= event;
629 } else {
630 // Although WSAAsyncSelect(..., 0), which is called from
631 // unregisterSocketNotifier(), immediately disables event message
632 // posting for the socket, it is possible that messages could be
633 // waiting in the application message queue even if the socket was
634 // closed. Also, some events could be implicitly re-enabled due
635 // to system calls. Ignore these superfluous events until all
636 // pending notifications have been suppressed. Next activation of
637 // socket notifiers will reset the mask.
638 d->active_fd.insert(sockfd, QSockFd(event, FD_READ | FD_CLOSE | FD_ACCEPT | FD_WRITE
639 | FD_CONNECT | FD_OOB));
640 }
641
642 d->postActivateSocketNotifiers();
643}
644
645void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
646{
647 Q_ASSERT(notifier);
648#ifndef QT_NO_DEBUG
649 qintptr sockfd = notifier->socket();
650 if (sockfd < 0) {
651 qWarning("QEventDispatcherWin32::unregisterSocketNotifier: invalid socket identifier");
652 return;
653 }
654 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
655 qWarning("QEventDispatcherWin32: socket notifiers cannot be disabled from another thread");
656 return;
657 }
658#endif
659 doUnregisterSocketNotifier(notifier);
660}
661
662void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier)
663{
664 Q_D(QEventDispatcherWin32);
665 int type = notifier->type();
666 qintptr sockfd = notifier->socket();
667 Q_ASSERT(sockfd >= 0);
668
669 QSFDict::iterator it = d->active_fd.find(sockfd);
670 if (it != d->active_fd.end()) {
671 QSockFd &sd = it.value();
672 if (sd.selected)
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];
676 if (sd.event == 0) {
677 d->active_fd.erase(it);
678 } else if (sd.selected) {
679 sd.selected = false;
680 d->postActivateSocketNotifiers();
681 }
682 }
683
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);
687 if (!sn)
688 return;
689
690 dict->remove(sockfd);
691 delete sn;
692}
693
694void QEventDispatcherWin32::registerTimer(Qt::TimerId timerId, Duration interval,
695 Qt::TimerType timerType, QObject *object)
696{
697#ifndef QT_NO_DEBUG
698 if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !object) {
699 qWarning("QEventDispatcherWin32::registerTimer: invalid arguments");
700 return;
701 }
702 if (object->thread() != thread() || thread() != QThread::currentThread()) {
703 qWarning("QEventDispatcherWin32::registerTimer: timers cannot be started from another thread");
704 return;
705 }
706#endif
707
708 Q_D(QEventDispatcherWin32);
709
710 // exiting ... do not register new timers
711 // (QCoreApplication::closingDown() is set too late to be used here)
712 if (d->closingDown)
713 return;
714
715 using namespace std::chrono;
716
717 WinTimerInfo *t = new WinTimerInfo;
718 t->dispatcher = this;
719 t->timerId = qToUnderlying(timerId);
720 // Windows does not have a ns-resolution timer
721 t->interval = ceil<milliseconds>(interval).count();
722 t->timerType = timerType;
723 t->obj = object;
724 t->inTimerEvent = false;
725 t->fastTimerId = 0;
726 t->usesExtendedInterval = false;
727 t->isSecondTimeout = false;
728
729 d->registerTimer(t);
730
731 d->timerDict.insert(t->timerId, t); // store timers in dict
732}
733
734bool QEventDispatcherWin32::unregisterTimer(Qt::TimerId timerId)
735{
736#ifndef QT_NO_DEBUG
737 if (qToUnderlying(timerId) < 1) {
738 qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument");
739 return false;
740 }
741 if (thread() != QThread::currentThread()) {
742 qWarning("QEventDispatcherWin32::unregisterTimer: timers cannot be stopped from another thread");
743 return false;
744 }
745#endif
746
747 Q_D(QEventDispatcherWin32);
748
749 WinTimerInfo *t = d->timerDict.take(qToUnderlying(timerId));
750 if (!t)
751 return false;
752
753 d->unregisterTimer(t);
754 return true;
755}
756
757bool QEventDispatcherWin32::unregisterTimers(QObject *object)
758{
759#ifndef QT_NO_DEBUG
760 if (!object) {
761 qWarning("QEventDispatcherWin32::unregisterTimers: invalid argument");
762 return false;
763 }
764 if (object->thread() != thread() || thread() != QThread::currentThread()) {
765 qWarning("QEventDispatcherWin32::unregisterTimers: timers cannot be stopped from another thread");
766 return false;
767 }
768#endif
769
770 Q_D(QEventDispatcherWin32);
771 if (d->timerDict.isEmpty())
772 return false;
773
774 auto it = d->timerDict.begin();
775 while (it != d->timerDict.end()) {
776 WinTimerInfo *t = it.value();
777 Q_ASSERT(t);
778 if (t->obj == object) {
779 it = d->timerDict.erase(it);
780 d->unregisterTimer(t);
781 } else {
782 ++it;
783 }
784 }
785 return true;
786}
787
788QList<QEventDispatcherWin32::TimerInfoV2>
789QEventDispatcherWin32::timersForObject(QObject *object) const
790{
791#ifndef QT_NO_DEBUG
792 if (!object) {
793 qWarning("QEventDispatcherWin32:registeredTimers: invalid argument");
794 return QList<TimerInfoV2>();
795 }
796#endif
797
798 Q_D(const QEventDispatcherWin32);
799 QList<TimerInfoV2> list;
800 for (WinTimerInfo *t : std::as_const(d->timerDict)) {
801 Q_ASSERT(t);
802 if (t->obj == object) {
803 list << TimerInfoV2{std::chrono::milliseconds{t->interval},
804 Qt::TimerId{t->timerId},
805 t->timerType};
806 }
807 }
808 return list;
809}
810
811QEventDispatcherWin32::Duration QEventDispatcherWin32::remainingTime(Qt::TimerId timerId) const
812{
813#ifndef QT_NO_DEBUG
814 if (qToUnderlying(timerId) < 1) {
815 qWarning("QEventDispatcherWin32::remainingTime: invalid argument");
816 return Duration::min();
817 }
818#endif
819
820 Q_D(const QEventDispatcherWin32);
821
822 WinTimerInfo *t = d->timerDict.value(qToUnderlying(timerId));
823 if (t) {
824 // timer found, return time to wait
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;
830 }
831
832#ifndef QT_NO_DEBUG
833 qWarning("QEventDispatcherWin32::remainingTime: timer id %d not found", qToUnderlying(timerId));
834#endif
835
836 return Duration::min();
837}
838
839void QEventDispatcherWin32::wakeUp()
840{
841 Q_D(QEventDispatcherWin32);
842 if (d->wakeUps.testAndSetRelaxed(0, 1)) {
843 // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending
844 if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0))
845 qErrnoWarning("QEventDispatcherWin32::wakeUp: Failed to post a message");
846 }
847}
848
849void QEventDispatcherWin32::interrupt()
850{
851 Q_D(QEventDispatcherWin32);
852 d->interrupt.storeRelaxed(true);
853 wakeUp();
854}
855
856void QEventDispatcherWin32::startingUp()
857{ }
858
859void QEventDispatcherWin32::closingDown()
860{
861 Q_D(QEventDispatcherWin32);
862
863 // clean up any socketnotifiers
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());
871
872 // clean up any timers
873 for (WinTimerInfo *t : std::as_const(d->timerDict))
874 d->unregisterTimer(t);
875 d->timerDict.clear();
876
877 d->closingDown = true;
878
879 if (d->sendPostedEventsTimerId != 0)
880 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
881 d->sendPostedEventsTimerId = 0;
882}
883
884bool QEventDispatcherWin32::event(QEvent *e)
885{
886 Q_D(QEventDispatcherWin32);
887 switch (e->type()) {
888 case QEvent::ZeroTimerEvent: {
889 QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e);
890 WinTimerInfo *t = d->timerDict.value(zte->timerId());
891 if (t) {
892 t->inTimerEvent = true;
893
894 QTimerEvent te(zte->timerId());
895 QCoreApplication::sendEvent(t->obj, &te);
896
897 // timer could have been removed
898 if (t->timerId == -1) {
899 delete t;
900 } else {
901 if (t->interval == 0 && t->inTimerEvent) {
902 // post the next zero timer event as long as the timer was not restarted
903 QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId()));
904 }
905
906 t->inTimerEvent = false;
907 }
908 }
909 return true;
910 }
911 case QEvent::Timer:
912 d->sendTimerEvent(static_cast<const QTimerEvent*>(e)->timerId());
913 break;
914 default:
915 break;
916 }
917 return QAbstractEventDispatcher::event(e);
918}
919
920void QEventDispatcherWin32::sendPostedEvents()
921{
922 Q_D(QEventDispatcherWin32);
923
924 if (d->sendPostedEventsTimerId != 0)
925 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
926 d->sendPostedEventsTimerId = 0;
927
928 // Allow posting WM_QT_SENDPOSTEDEVENTS message.
929 d->wakeUps.storeRelaxed(0);
930
931 QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData.loadRelaxed());
932}
933
934HWND QEventDispatcherWin32::internalHwnd()
935{
936 return d_func()->internalHwnd;
937}
938
939QT_END_NAMESPACE
940
941#include "moc_qeventdispatcher_win_p.cpp"
Combined button and popup list for selecting options.
static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher)
static quint64 qt_msectime()
#define TIME_KILL_SYNCHRONOUS
#define WM_GESTURE
@ SendPostedEventsTimerId
#define WM_GESTURENOTIFY
#define DWORD_PTR
@ WM_QT_ACTIVATENOTIFIERS
@ WM_QT_SOCKETNOTIFIER
@ WM_QT_SENDPOSTEDEVENTS
#define WM_TOUCH
static bool isUserInputMessage(UINT message)
static ULONG calculateNextTimeout(WinTimerInfo *t, quint64 currentTime)