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::saturate_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::saturate_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
372 if (!ok) {
373 // user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
374 ok = SetCoalescableTimer(internalHwnd, t->timerId, interval, nullptr, tolerance);
375 }
376 if (!ok)
377 ok = SetTimer(internalHwnd, t->timerId, interval, nullptr);
378
379 if (!ok)
380 qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
381}
382
383void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
384{
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);
390 } else {
391 KillTimer(internalHwnd, t->timerId);
392 }
393 t->timerId = -1;
394 if (!t->inTimerEvent)
395 delete t;
396}
397
398void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
399{
400 WinTimerInfo *t = timerDict.value(timerId);
401 if (t && !t->inTimerEvent) {
402 if (t->usesExtendedInterval && !t->isSecondTimeout) {
403 // That's the case when the interval is larger than uint
404 t->isSecondTimeout = true;
405 return;
406 }
407
408 // send event, but don't allow it to recurse
409 t->inTimerEvent = true;
410
411 // recalculate next emission
412 calculateNextTimeout(t, qt_msectime());
413
414 QTimerEvent e(t->timerId);
415 QCoreApplication::sendEvent(t->obj, &e);
416
417 // timer could have been removed
418 if (t->timerId == -1) {
419 delete t;
420 } else {
421 t->isSecondTimeout = false;
422 t->inTimerEvent = false;
423 }
424 }
425}
426
427void QEventDispatcherWin32Private::doWsaAsyncSelect(qintptr socket, long event)
428{
429 Q_ASSERT(internalHwnd);
430 // BoundsChecker may emit a warning for WSAAsyncSelect when event == 0
431 // This is a BoundsChecker bug and not a Qt bug
432 WSAAsyncSelect(socket, internalHwnd, event ? int(WM_QT_SOCKETNOTIFIER) : 0, event);
433}
434
435void QEventDispatcherWin32Private::postActivateSocketNotifiers()
436{
437 if (!activateNotifiersPosted)
438 activateNotifiersPosted = PostMessage(internalHwnd, WM_QT_ACTIVATENOTIFIERS, 0, 0);
439}
440
441QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
442 : QEventDispatcherWin32(*new QEventDispatcherWin32Private, parent)
443{
444}
445
446QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
447 : QAbstractEventDispatcherV2(dd, parent)
448{
449 Q_D(QEventDispatcherWin32);
450
451 d->internalHwnd = qt_create_internal_window(this);
452}
453
454QEventDispatcherWin32::~QEventDispatcherWin32()
455{
456}
457
458static bool isUserInputMessage(UINT message)
459{
460 return (message >= WM_KEYFIRST && message <= WM_KEYLAST)
461 || (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST)
462 || message == WM_MOUSEWHEEL
463 || message == WM_MOUSEHWHEEL
464 || message == WM_TOUCH
465#ifndef QT_NO_GESTURES
466 || message == WM_GESTURE
467 || message == WM_GESTURENOTIFY
468#endif
469// Pointer input: Exclude WM_NCPOINTERUPDATE .. WM_POINTERROUTEDRELEASED
470 || (message >= 0x0241 && message <= 0x0253)
471 || message == WM_CLOSE;
472}
473
474bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
475{
476 Q_D(QEventDispatcherWin32);
477
478 // We don't know _when_ the interrupt occurred so we have to honor it.
479 const bool wasInterrupted = d->interrupt.fetchAndStoreRelaxed(false);
480 emit awake();
481
482 // To prevent livelocks, send posted events once per iteration.
483 // QCoreApplication::sendPostedEvents() takes care about recursions.
484 sendPostedEvents();
485
486 if (wasInterrupted)
487 return false;
488
489 auto threadData = d->threadData.loadRelaxed();
490 bool canWait;
491 bool retVal = false;
492 do {
493 QVarLengthArray<MSG> processedTimers;
494 while (!d->interrupt.loadRelaxed()) {
495 MSG msg;
496
497 if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
498 // process queued user input events
499 msg = d->queuedUserInputEvents.takeFirst();
500 } else if (!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
501 // process queued socket events
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)) {
506 // queue user input events for later processing
507 d->queuedUserInputEvents.append(msg);
508 continue;
509 }
510 if ((flags & QEventLoop::ExcludeSocketNotifiers)
511 && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
512 // queue socket events for later processing
513 d->queuedSocketEvents.append(msg);
514 continue;
515 }
516 } else if (MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, MWMO_ALERTABLE)
517 == WAIT_OBJECT_0) {
518 // a new message has arrived, process it
519 continue;
520 } else {
521 // nothing to do, so break
522 break;
523 }
524
525 if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
526 d->startPostedEventsTimer();
527 // Set result to 'true' because the message was sent by wakeUp().
528 retVal = true;
529 continue;
530 }
531 if (msg.message == WM_TIMER) {
532 // Skip timer event intended for use inside foreign loop.
533 if (d->internalHwnd == msg.hwnd && msg.wParam == d->sendPostedEventsTimerId)
534 continue;
535
536 // avoid live-lock by keeping track of the timers we've already sent
537 bool found = false;
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);
541 }
542 if (found)
543 continue;
544 processedTimers.append(msg);
545 } else if (msg.message == WM_QUIT) {
546 if (QCoreApplication::instance())
547 QCoreApplication::instance()->quit();
548 return false;
549 }
550
551 if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) {
552 TranslateMessage(&msg);
553 DispatchMessage(&msg);
554 }
555 retVal = true;
556 }
557
558 // wait for message
559 canWait = (!retVal
560 && !d->interrupt.loadRelaxed()
561 && flags.testFlag(QEventLoop::WaitForMoreEvents)
562 && threadData->canWaitLocked());
563 if (canWait) {
564 emit aboutToBlock();
565 MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
566 emit awake();
567 }
568 } while (canWait);
569
570 return retVal;
571}
572
573void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
574{
575 Q_ASSERT(notifier);
576 qintptr sockfd = notifier->socket();
577 int type = notifier->type();
578#ifndef QT_NO_DEBUG
579 if (sockfd < 0) {
580 qWarning("QEventDispatcherWin32::registerSocketNotifier: invalid socket identifier");
581 return;
582 }
583 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
584 qWarning("QEventDispatcherWin32: socket notifiers cannot be enabled from another thread");
585 return;
586 }
587#endif
588
589 Q_D(QEventDispatcherWin32);
590 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
591 QSNDict *dict = sn_vec[type];
592
593 if (QCoreApplication::closingDown()) // ### d->exitloop?
594 return; // after sn_cleanup, don't reinitialize.
595
596 if (dict->contains(sockfd)) {
597 const char *t[] = { "Read", "Write", "Exception" };
598 /* Variable "socket" below is a function pointer. */
599 qWarning("QSocketNotifier: Multiple socket notifiers for "
600 "same socket %" PRIdQINTPTR " and type %s", sockfd, t[type]);
601 }
602
603 QSockNot *sn = new QSockNot;
604 sn->obj = notifier;
605 sn->fd = sockfd;
606 dict->insert(sn->fd, sn);
607
608 long event = 0;
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))
614 event |= FD_OOB;
615
616 QSFDict::iterator it = d->active_fd.find(sockfd);
617 if (it != d->active_fd.end()) {
618 QSockFd &sd = it.value();
619 if (sd.selected) {
620 d->doWsaAsyncSelect(sockfd, 0);
621 sd.selected = false;
622 }
623 sd.event |= event;
624 } else {
625 // Although WSAAsyncSelect(..., 0), which is called from
626 // unregisterSocketNotifier(), immediately disables event message
627 // posting for the socket, it is possible that messages could be
628 // waiting in the application message queue even if the socket was
629 // closed. Also, some events could be implicitly re-enabled due
630 // to system calls. Ignore these superfluous events until all
631 // pending notifications have been suppressed. Next activation of
632 // socket notifiers will reset the mask.
633 d->active_fd.insert(sockfd, QSockFd(event, FD_READ | FD_CLOSE | FD_ACCEPT | FD_WRITE
634 | FD_CONNECT | FD_OOB));
635 }
636
637 d->postActivateSocketNotifiers();
638}
639
640void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
641{
642 Q_ASSERT(notifier);
643#ifndef QT_NO_DEBUG
644 qintptr sockfd = notifier->socket();
645 if (sockfd < 0) {
646 qWarning("QEventDispatcherWin32::unregisterSocketNotifier: invalid socket identifier");
647 return;
648 }
649 if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
650 qWarning("QEventDispatcherWin32: socket notifiers cannot be disabled from another thread");
651 return;
652 }
653#endif
654 doUnregisterSocketNotifier(notifier);
655}
656
657void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier)
658{
659 Q_D(QEventDispatcherWin32);
660 int type = notifier->type();
661 qintptr sockfd = notifier->socket();
662 Q_ASSERT(sockfd >= 0);
663
664 QSFDict::iterator it = d->active_fd.find(sockfd);
665 if (it != d->active_fd.end()) {
666 QSockFd &sd = it.value();
667 if (sd.selected)
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];
671 if (sd.event == 0) {
672 d->active_fd.erase(it);
673 } else if (sd.selected) {
674 sd.selected = false;
675 d->postActivateSocketNotifiers();
676 }
677 }
678
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);
682 if (!sn)
683 return;
684
685 dict->remove(sockfd);
686 delete sn;
687}
688
689void QEventDispatcherWin32::registerTimer(Qt::TimerId timerId, Duration interval,
690 Qt::TimerType timerType, QObject *object)
691{
692#ifndef QT_NO_DEBUG
693 if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !object) {
694 qWarning("QEventDispatcherWin32::registerTimer: invalid arguments");
695 return;
696 }
697 if (object->thread() != thread() || thread() != QThread::currentThread()) {
698 qWarning("QEventDispatcherWin32::registerTimer: timers cannot be started from another thread");
699 return;
700 }
701#endif
702
703 Q_D(QEventDispatcherWin32);
704
705 // exiting ... do not register new timers
706 // (QCoreApplication::closingDown() is set too late to be used here)
707 if (d->closingDown)
708 return;
709
710 using namespace std::chrono;
711
712 WinTimerInfo *t = new WinTimerInfo;
713 t->dispatcher = this;
714 t->timerId = qToUnderlying(timerId);
715 // Windows does not have a ns-resolution timer
716 t->interval = ceil<milliseconds>(interval).count();
717 t->timerType = timerType;
718 t->obj = object;
719 t->inTimerEvent = false;
720 t->fastTimerId = 0;
721 t->usesExtendedInterval = false;
722 t->isSecondTimeout = false;
723
724 d->registerTimer(t);
725
726 d->timerDict.insert(t->timerId, t); // store timers in dict
727}
728
729bool QEventDispatcherWin32::unregisterTimer(Qt::TimerId timerId)
730{
731#ifndef QT_NO_DEBUG
732 if (qToUnderlying(timerId) < 1) {
733 qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument");
734 return false;
735 }
736 if (thread() != QThread::currentThread()) {
737 qWarning("QEventDispatcherWin32::unregisterTimer: timers cannot be stopped from another thread");
738 return false;
739 }
740#endif
741
742 Q_D(QEventDispatcherWin32);
743
744 WinTimerInfo *t = d->timerDict.take(qToUnderlying(timerId));
745 if (!t)
746 return false;
747
748 d->unregisterTimer(t);
749 return true;
750}
751
752bool QEventDispatcherWin32::unregisterTimers(QObject *object)
753{
754#ifndef QT_NO_DEBUG
755 if (!object) {
756 qWarning("QEventDispatcherWin32::unregisterTimers: invalid argument");
757 return false;
758 }
759 if (object->thread() != thread() || thread() != QThread::currentThread()) {
760 qWarning("QEventDispatcherWin32::unregisterTimers: timers cannot be stopped from another thread");
761 return false;
762 }
763#endif
764
765 Q_D(QEventDispatcherWin32);
766 if (d->timerDict.isEmpty())
767 return false;
768
769 auto it = d->timerDict.begin();
770 while (it != d->timerDict.end()) {
771 WinTimerInfo *t = it.value();
772 Q_ASSERT(t);
773 if (t->obj == object) {
774 it = d->timerDict.erase(it);
775 d->unregisterTimer(t);
776 } else {
777 ++it;
778 }
779 }
780 return true;
781}
782
783QList<QEventDispatcherWin32::TimerInfoV2>
784QEventDispatcherWin32::timersForObject(QObject *object) const
785{
786#ifndef QT_NO_DEBUG
787 if (!object) {
788 qWarning("QEventDispatcherWin32:registeredTimers: invalid argument");
789 return QList<TimerInfoV2>();
790 }
791#endif
792
793 Q_D(const QEventDispatcherWin32);
794 QList<TimerInfoV2> list;
795 for (WinTimerInfo *t : std::as_const(d->timerDict)) {
796 Q_ASSERT(t);
797 if (t->obj == object) {
798 list << TimerInfoV2{std::chrono::milliseconds{t->interval},
799 Qt::TimerId{t->timerId},
800 t->timerType};
801 }
802 }
803 return list;
804}
805
806QEventDispatcherWin32::Duration QEventDispatcherWin32::remainingTime(Qt::TimerId timerId) const
807{
808#ifndef QT_NO_DEBUG
809 if (qToUnderlying(timerId) < 1) {
810 qWarning("QEventDispatcherWin32::remainingTime: invalid argument");
811 return Duration::min();
812 }
813#endif
814
815 Q_D(const QEventDispatcherWin32);
816
817 WinTimerInfo *t = d->timerDict.value(qToUnderlying(timerId));
818 if (t) {
819 // timer found, return time to wait
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;
825 }
826
827#ifndef QT_NO_DEBUG
828 qWarning("QEventDispatcherWin32::remainingTime: timer id %d not found", qToUnderlying(timerId));
829#endif
830
831 return Duration::min();
832}
833
834void QEventDispatcherWin32::wakeUp()
835{
836 Q_D(QEventDispatcherWin32);
837 if (d->wakeUps.testAndSetRelaxed(0, 1)) {
838 // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending
839 if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0))
840 qErrnoWarning("QEventDispatcherWin32::wakeUp: Failed to post a message");
841 }
842}
843
844void QEventDispatcherWin32::interrupt()
845{
846 Q_D(QEventDispatcherWin32);
847 d->interrupt.storeRelaxed(true);
848 wakeUp();
849}
850
851void QEventDispatcherWin32::startingUp()
852{ }
853
854void QEventDispatcherWin32::closingDown()
855{
856 Q_D(QEventDispatcherWin32);
857
858 // clean up any socketnotifiers
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());
866
867 // clean up any timers
868 for (WinTimerInfo *t : std::as_const(d->timerDict))
869 d->unregisterTimer(t);
870 d->timerDict.clear();
871
872 d->closingDown = true;
873
874 if (d->sendPostedEventsTimerId != 0)
875 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
876 d->sendPostedEventsTimerId = 0;
877}
878
879bool QEventDispatcherWin32::event(QEvent *e)
880{
881 Q_D(QEventDispatcherWin32);
882 switch (e->type()) {
883 case QEvent::ZeroTimerEvent: {
884 QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e);
885 WinTimerInfo *t = d->timerDict.value(zte->timerId());
886 if (t) {
887 t->inTimerEvent = true;
888
889 QTimerEvent te(zte->timerId());
890 QCoreApplication::sendEvent(t->obj, &te);
891
892 // timer could have been removed
893 if (t->timerId == -1) {
894 delete t;
895 } else {
896 if (t->interval == 0 && t->inTimerEvent) {
897 // post the next zero timer event as long as the timer was not restarted
898 QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId()));
899 }
900
901 t->inTimerEvent = false;
902 }
903 }
904 return true;
905 }
906 case QEvent::Timer:
907 d->sendTimerEvent(static_cast<const QTimerEvent*>(e)->timerId());
908 break;
909 default:
910 break;
911 }
912 return QAbstractEventDispatcher::event(e);
913}
914
915void QEventDispatcherWin32::sendPostedEvents()
916{
917 Q_D(QEventDispatcherWin32);
918
919 if (d->sendPostedEventsTimerId != 0)
920 KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
921 d->sendPostedEventsTimerId = 0;
922
923 // Allow posting WM_QT_SENDPOSTEDEVENTS message.
924 d->wakeUps.storeRelaxed(0);
925
926 QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData.loadRelaxed());
927}
928
929HWND QEventDispatcherWin32::internalHwnd()
930{
931 return d_func()->internalHwnd;
932}
933
934QT_END_NAMESPACE
935
936#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)