1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "qeventdispatcher_win_p.h"
42 
43 #include "qcoreapplication.h"
44 #include <private/qsystemlibrary_p.h>
45 #include "qoperatingsystemversion.h"
46 #include "qpair.h"
47 #include "qset.h"
48 #include "qsocketnotifier.h"
49 #include "qvarlengtharray.h"
50 #include "qwineventnotifier.h"
51 
52 #include "qelapsedtimer.h"
53 #include "qcoreapplication_p.h"
54 #include <private/qthread_p.h>
55 #include <private/qwineventnotifier_p.h>
56 
57 QT_BEGIN_NAMESPACE
58 
59 extern uint qGlobalPostedEventsCount();
60 
61 #ifndef TIME_KILL_SYNCHRONOUS
62 #  define TIME_KILL_SYNCHRONOUS 0x0100
63 #endif
64 
65 #ifndef QS_RAWINPUT
66 #  define QS_RAWINPUT 0x0400
67 #endif
68 
69 #ifndef WM_TOUCH
70 #  define WM_TOUCH 0x0240
71 #endif
72 #ifndef QT_NO_GESTURES
73 #ifndef WM_GESTURE
74 #  define WM_GESTURE 0x0119
75 #endif
76 #ifndef WM_GESTURENOTIFY
77 #  define WM_GESTURENOTIFY 0x011A
78 #endif
79 #endif // QT_NO_GESTURES
80 
81 enum {
82     WM_QT_SOCKETNOTIFIER = WM_USER,
83     WM_QT_SENDPOSTEDEVENTS = WM_USER + 1,
84     WM_QT_ACTIVATENOTIFIERS = WM_USER + 2
85 };
86 
87 enum {
88     SendPostedEventsTimerId = ~1u
89 };
90 
91 class QEventDispatcherWin32Private;
92 
93 #if !defined(DWORD_PTR) && !defined(Q_OS_WIN64)
94 #define DWORD_PTR DWORD
95 #endif
96 
97 LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
98 
QEventDispatcherWin32Private()99 QEventDispatcherWin32Private::QEventDispatcherWin32Private()
100     : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0),
101       getMessageHook(0), sendPostedEventsTimerId(0), wakeUps(0),
102       activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL)
103 {
104 }
105 
~QEventDispatcherWin32Private()106 QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
107 {
108     if (winEventNotifierActivatedEvent)
109         CloseHandle(winEventNotifierActivatedEvent);
110     if (internalHwnd)
111         DestroyWindow(internalHwnd);
112 }
113 
activateEventNotifier(QWinEventNotifier * wen)114 void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen)
115 {
116     QEvent event(QEvent::WinEventAct);
117     QCoreApplication::sendEvent(wen, &event);
118 }
119 
120 // This function is called by a workerthread
qt_fast_timer_proc(uint timerId,uint,DWORD_PTR user,DWORD_PTR,DWORD_PTR)121 void WINAPI QT_WIN_CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/)
122 {
123     if (!timerId) // sanity check
124         return;
125     auto t = reinterpret_cast<WinTimerInfo*>(user);
126     Q_ASSERT(t);
127     QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId));
128 }
129 
inputQueueMask()130 static inline UINT inputQueueMask()
131 {
132     UINT result = QS_ALLEVENTS;
133     // QTBUG 28513, QTBUG-29097, QTBUG-29435: QS_TOUCH, QS_POINTER became part of
134     // QS_INPUT in Windows Kit 8. They should not be used when running on pre-Windows 8.
135 #if WINVER > 0x0601
136     if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8)
137         result &= ~(QS_TOUCH | QS_POINTER);
138 #endif //  WINVER > 0x0601
139     return result;
140 }
141 
qt_internal_proc(HWND hwnd,UINT message,WPARAM wp,LPARAM lp)142 LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
143 {
144     if (message == WM_NCCREATE)
145         return true;
146 
147     MSG msg;
148     msg.hwnd = hwnd;
149     msg.message = message;
150     msg.wParam = wp;
151     msg.lParam = lp;
152     QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
153 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
154     qintptr result;
155 #else
156     long result;
157 #endif
158     if (!dispatcher) {
159         if (message == WM_TIMER)
160             KillTimer(hwnd, wp);
161         return 0;
162     }
163     if (dispatcher->filterNativeEvent(QByteArrayLiteral("windows_dispatcher_MSG"), &msg, &result))
164         return result;
165 
166 #ifdef GWLP_USERDATA
167     auto q = reinterpret_cast<QEventDispatcherWin32 *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
168 #else
169     auto q = reinterpret_cast<QEventDispatcherWin32 *>(GetWindowLong(hwnd, GWL_USERDATA));
170 #endif
171     QEventDispatcherWin32Private *d = 0;
172     if (q != 0)
173         d = q->d_func();
174 
175     switch (message) {
176     case WM_QT_SOCKETNOTIFIER: {
177         // socket notifier message
178         int type = -1;
179         switch (WSAGETSELECTEVENT(lp)) {
180         case FD_READ:
181         case FD_ACCEPT:
182             type = 0;
183             break;
184         case FD_WRITE:
185         case FD_CONNECT:
186             type = 1;
187             break;
188         case FD_OOB:
189             type = 2;
190             break;
191         case FD_CLOSE:
192             type = 3;
193             break;
194         }
195         if (type >= 0) {
196             Q_ASSERT(d != 0);
197             QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read };
198             QSNDict *dict = sn_vec[type];
199 
200             QSockNot *sn = dict ? dict->value(wp) : 0;
201             if (sn == nullptr) {
202                 d->postActivateSocketNotifiers();
203             } else {
204                 Q_ASSERT(d->active_fd.contains(sn->fd));
205                 QSockFd &sd = d->active_fd[sn->fd];
206                 if (sd.selected) {
207                     Q_ASSERT(sd.mask == 0);
208                     d->doWsaAsyncSelect(sn->fd, 0);
209                     sd.selected = false;
210                 }
211                 d->postActivateSocketNotifiers();
212 
213                 // Ignore the message if a notification with the same type was
214                 // received previously. Suppressed message is definitely spurious.
215                 const long eventCode = WSAGETSELECTEVENT(lp);
216                 if ((sd.mask & eventCode) != eventCode) {
217                     sd.mask |= eventCode;
218                     QEvent event(type < 3 ? QEvent::SockAct : QEvent::SockClose);
219                     QCoreApplication::sendEvent(sn->obj, &event);
220                 }
221             }
222         }
223         return 0;
224     }
225     case WM_QT_ACTIVATENOTIFIERS: {
226         Q_ASSERT(d != 0);
227 
228         // Postpone activation if we have unhandled socket notifier messages
229         // in the queue. WM_QT_ACTIVATENOTIFIERS will be posted again as a result of
230         // event processing.
231         MSG msg;
232         if (!PeekMessage(&msg, d->internalHwnd,
233                          WM_QT_SOCKETNOTIFIER, WM_QT_SOCKETNOTIFIER, PM_NOREMOVE)
234             && d->queuedSocketEvents.isEmpty()) {
235             // register all socket notifiers
236             for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end();
237                  it != end; ++it) {
238                 QSockFd &sd = it.value();
239                 if (!sd.selected) {
240                     d->doWsaAsyncSelect(it.key(), sd.event);
241                     // allow any event to be accepted
242                     sd.mask = 0;
243                     sd.selected = true;
244                 }
245             }
246         }
247         d->activateNotifiersPosted = false;
248         return 0;
249     }
250     case WM_TIMER:
251         Q_ASSERT(d != 0);
252 
253         if (wp == d->sendPostedEventsTimerId)
254             q->sendPostedEvents();
255         else
256             d->sendTimerEvent(wp);
257         return 0;
258     case WM_QT_SENDPOSTEDEVENTS:
259         Q_ASSERT(d != 0);
260 
261         // We send posted events manually, if the window procedure was invoked
262         // by the foreign event loop (e.g. from the native modal dialog).
263         // Skip sending, if the message queue is not empty.
264         // sendPostedEventsTimer will deliver posted events later.
265         static const UINT mask = inputQueueMask();
266         if (HIWORD(GetQueueStatus(mask)) == 0)
267             q->sendPostedEvents();
268         return 0;
269     } // switch (message)
270 
271     return DefWindowProc(hwnd, message, wp, lp);
272 }
273 
qt_GetMessageHook(int code,WPARAM wp,LPARAM lp)274 LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
275 {
276     QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
277     Q_ASSERT(q != 0);
278     QEventDispatcherWin32Private *d = q->d_func();
279     MSG *msg = reinterpret_cast<MSG *>(lp);
280     // Windows unexpectedly passes PM_NOYIELD flag to the hook procedure,
281     // if ::PeekMessage(..., PM_REMOVE | PM_NOYIELD) is called from the event loop.
282     // So, retrieve 'removed' tag as a bit field.
283     const bool messageRemoved = (wp & PM_REMOVE) != 0;
284 
285     if (msg->hwnd == d->internalHwnd && msg->message == WM_QT_SENDPOSTEDEVENTS
286         && messageRemoved && d->sendPostedEventsTimerId == 0) {
287         // Start a timer to deliver posted events when the message queue is emptied.
288         d->sendPostedEventsTimerId = SetTimer(d->internalHwnd, SendPostedEventsTimerId,
289                                               USER_TIMER_MINIMUM, NULL);
290     }
291     return d->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0;
292 }
293 
294 // Provide class name and atom for the message window used by
295 // QEventDispatcherWin32Private via Q_GLOBAL_STATIC shared between threads.
296 struct QWindowsMessageWindowClassContext
297 {
298     QWindowsMessageWindowClassContext();
299     ~QWindowsMessageWindowClassContext();
300 
301     ATOM atom;
302     wchar_t *className;
303 };
304 
QWindowsMessageWindowClassContext()305 QWindowsMessageWindowClassContext::QWindowsMessageWindowClassContext()
306     : atom(0), className(0)
307 {
308     // make sure that multiple Qt's can coexist in the same process
309     const QString qClassName = QStringLiteral("QEventDispatcherWin32_Internal_Widget")
310         + QString::number(quintptr(qt_internal_proc));
311     className = new wchar_t[qClassName.size() + 1];
312     qClassName.toWCharArray(className);
313     className[qClassName.size()] = 0;
314 
315     WNDCLASS wc;
316     wc.style = 0;
317     wc.lpfnWndProc = qt_internal_proc;
318     wc.cbClsExtra = 0;
319     wc.cbWndExtra = 0;
320     wc.hInstance = GetModuleHandle(0);
321     wc.hIcon = 0;
322     wc.hCursor = 0;
323     wc.hbrBackground = 0;
324     wc.lpszMenuName = NULL;
325     wc.lpszClassName = className;
326     atom = RegisterClass(&wc);
327     if (!atom) {
328         qErrnoWarning("%ls RegisterClass() failed", qUtf16Printable(qClassName));
329         delete [] className;
330         className = 0;
331     }
332 }
333 
~QWindowsMessageWindowClassContext()334 QWindowsMessageWindowClassContext::~QWindowsMessageWindowClassContext()
335 {
336     if (className) {
337         UnregisterClass(className, GetModuleHandle(0));
338         delete [] className;
339     }
340 }
341 
Q_GLOBAL_STATIC(QWindowsMessageWindowClassContext,qWindowsMessageWindowClassContext)342 Q_GLOBAL_STATIC(QWindowsMessageWindowClassContext, qWindowsMessageWindowClassContext)
343 
344 static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher)
345 {
346     QWindowsMessageWindowClassContext *ctx = qWindowsMessageWindowClassContext();
347     if (!ctx->atom)
348         return 0;
349     HWND wnd = CreateWindow(ctx->className,    // classname
350                             ctx->className,    // window name
351                             0,                 // style
352                             0, 0, 0, 0,        // geometry
353                             HWND_MESSAGE,            // parent
354                             0,                 // menu handle
355                             GetModuleHandle(0),     // application
356                             0);                // windows creation data.
357 
358     if (!wnd) {
359         qErrnoWarning("CreateWindow() for QEventDispatcherWin32 internal window failed");
360         return 0;
361     }
362 
363 #ifdef GWLP_USERDATA
364     SetWindowLongPtr(wnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(eventDispatcher));
365 #else
366     SetWindowLong(wnd, GWL_USERDATA, reinterpret_cast<LONG>(eventDispatcher));
367 #endif
368 
369     return wnd;
370 }
371 
calculateNextTimeout(WinTimerInfo * t,quint64 currentTime)372 static void calculateNextTimeout(WinTimerInfo *t, quint64 currentTime)
373 {
374     uint interval = t->interval;
375     if ((interval >= 20000u && t->timerType != Qt::PreciseTimer) || t->timerType == Qt::VeryCoarseTimer) {
376         // round the interval, VeryCoarseTimers only have full second accuracy
377         interval = ((interval + 500)) / 1000 * 1000;
378     }
379     t->interval = interval;
380     t->timeout = currentTime + interval;
381 }
382 
registerTimer(WinTimerInfo * t)383 void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
384 {
385     Q_ASSERT(internalHwnd);
386 
387     Q_Q(QEventDispatcherWin32);
388 
389     bool ok = false;
390     calculateNextTimeout(t, qt_msectime());
391     uint interval = t->interval;
392     if (interval == 0u) {
393         // optimization for single-shot-zero-timer
394         QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
395         ok = true;
396     } else if (interval < 20u || t->timerType == Qt::PreciseTimer) {
397         // 3/2016: Although MSDN states timeSetEvent() is deprecated, the function
398         // is still deemed to be the most reliable precision timer.
399         t->fastTimerId = timeSetEvent(interval, 1, qt_fast_timer_proc, DWORD_PTR(t),
400                                       TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
401         ok = t->fastTimerId;
402     }
403 
404     if (!ok) {
405         // user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
406         ok = SetTimer(internalHwnd, t->timerId, interval, 0);
407     }
408 
409     if (!ok)
410         qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
411 }
412 
unregisterTimer(WinTimerInfo * t)413 void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t)
414 {
415     if (t->interval == 0) {
416         QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
417     } else if (t->fastTimerId != 0) {
418         timeKillEvent(t->fastTimerId);
419         QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
420     } else if (internalHwnd) {
421         KillTimer(internalHwnd, t->timerId);
422     }
423     t->timerId = -1;
424     if (!t->inTimerEvent)
425         delete t;
426 }
427 
sendTimerEvent(int timerId)428 void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
429 {
430     WinTimerInfo *t = timerDict.value(timerId);
431     if (t && !t->inTimerEvent) {
432         // send event, but don't allow it to recurse
433         t->inTimerEvent = true;
434 
435         // recalculate next emission
436         calculateNextTimeout(t, qt_msectime());
437 
438         QTimerEvent e(t->timerId);
439         QCoreApplication::sendEvent(t->obj, &e);
440 
441         // timer could have been removed
442         if (t->timerId == -1) {
443             delete t;
444         } else {
445             t->inTimerEvent = false;
446         }
447     }
448 }
449 
doWsaAsyncSelect(int socket,long event)450 void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket, long event)
451 {
452     Q_ASSERT(internalHwnd);
453     // BoundsChecker may emit a warning for WSAAsyncSelect when event == 0
454     // This is a BoundsChecker bug and not a Qt bug
455     WSAAsyncSelect(socket, internalHwnd, event ? int(WM_QT_SOCKETNOTIFIER) : 0, event);
456 }
457 
postActivateSocketNotifiers()458 void QEventDispatcherWin32Private::postActivateSocketNotifiers()
459 {
460     if (!activateNotifiersPosted)
461         activateNotifiersPosted = PostMessage(internalHwnd, WM_QT_ACTIVATENOTIFIERS, 0, 0);
462 }
463 
createInternalHwnd()464 void QEventDispatcherWin32::createInternalHwnd()
465 {
466     Q_D(QEventDispatcherWin32);
467 
468     if (d->internalHwnd)
469         return;
470     d->internalHwnd = qt_create_internal_window(this);
471 
472     // setup GetMessage hook needed to drive our posted events
473     d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
474     if (Q_UNLIKELY(!d->getMessageHook)) {
475         int errorCode = GetLastError();
476         qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %ls",
477                errorCode, qUtf16Printable(qt_error_string(errorCode)));
478     }
479 
480     // start all normal timers
481     for (int i = 0; i < d->timerVec.count(); ++i)
482         d->registerTimer(d->timerVec.at(i));
483 }
484 
QEventDispatcherWin32(QObject * parent)485 QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
486     : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent)
487 {
488 }
489 
QEventDispatcherWin32(QEventDispatcherWin32Private & dd,QObject * parent)490 QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
491     : QAbstractEventDispatcher(dd, parent)
492 { }
493 
~QEventDispatcherWin32()494 QEventDispatcherWin32::~QEventDispatcherWin32()
495 {
496 }
497 
isUserInputMessage(UINT message)498 static bool isUserInputMessage(UINT message)
499 {
500     return (message >= WM_KEYFIRST && message <= WM_KEYLAST)
501         || (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST)
502         || message == WM_MOUSEWHEEL
503         || message == WM_MOUSEHWHEEL
504         || message == WM_TOUCH
505 #ifndef QT_NO_GESTURES
506         || message == WM_GESTURE
507         || message == WM_GESTURENOTIFY
508 #endif
509 // Pointer input: Exclude WM_NCPOINTERUPDATE .. WM_POINTERROUTEDRELEASED
510         || (message >= 0x0241 && message <= 0x0253)
511         || message == WM_CLOSE;
512 }
513 
processEvents(QEventLoop::ProcessEventsFlags flags)514 bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
515 {
516     Q_D(QEventDispatcherWin32);
517 
518     if (!d->internalHwnd) {
519         createInternalHwnd();
520         wakeUp(); // trigger a call to sendPostedEvents()
521     }
522 
523     d->interrupt.storeRelaxed(false);
524     emit awake();
525 
526     // To prevent livelocks, send posted events once per iteration.
527     // QCoreApplication::sendPostedEvents() takes care about recursions.
528     sendPostedEvents();
529 
530     auto threadData = d->threadData.loadRelaxed();
531     bool canWait;
532     bool retVal = false;
533     do {
534         DWORD waitRet = 0;
535         DWORD nCount = 0;
536         HANDLE *pHandles = nullptr;
537         if (d->winEventNotifierActivatedEvent) {
538             nCount = 1;
539             pHandles = &d->winEventNotifierActivatedEvent;
540         }
541         QVarLengthArray<MSG> processedTimers;
542         while (!d->interrupt.loadRelaxed()) {
543             MSG msg;
544             bool haveMessage;
545 
546             if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
547                 // process queued user input events
548                 haveMessage = true;
549                 msg = d->queuedUserInputEvents.takeFirst();
550             } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
551                 // process queued socket events
552                 haveMessage = true;
553                 msg = d->queuedSocketEvents.takeFirst();
554             } else {
555                 haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
556                 if (haveMessage) {
557                     if (flags.testFlag(QEventLoop::ExcludeUserInputEvents)
558                         && isUserInputMessage(msg.message)) {
559                         // queue user input events for later processing
560                         d->queuedUserInputEvents.append(msg);
561                         continue;
562                     }
563                     if ((flags & QEventLoop::ExcludeSocketNotifiers)
564                         && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
565                         // queue socket events for later processing
566                         d->queuedSocketEvents.append(msg);
567                         continue;
568                     }
569                 }
570             }
571             if (!haveMessage) {
572                 // no message - check for signalled objects
573                 waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE);
574                 if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) {
575                     // a new message has arrived, process it
576                     continue;
577                 }
578             }
579             if (haveMessage) {
580                 if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
581                     // Set result to 'true' because the message was sent by wakeUp().
582                     retVal = true;
583                     continue;
584                 }
585                 if (msg.message == WM_TIMER) {
586                     // Skip timer event intended for use inside foreign loop.
587                     if (d->internalHwnd == msg.hwnd && msg.wParam == d->sendPostedEventsTimerId)
588                         continue;
589 
590                     // avoid live-lock by keeping track of the timers we've already sent
591                     bool found = false;
592                     for (int i = 0; !found && i < processedTimers.count(); ++i) {
593                         const MSG processed = processedTimers.constData()[i];
594                         found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
595                     }
596                     if (found)
597                         continue;
598                     processedTimers.append(msg);
599                 } else if (msg.message == WM_QUIT) {
600                     if (QCoreApplication::instance())
601                         QCoreApplication::instance()->quit();
602                     return false;
603                 }
604 
605                 if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) {
606                     TranslateMessage(&msg);
607                     DispatchMessage(&msg);
608                 }
609             } else if (waitRet - WAIT_OBJECT_0 < nCount) {
610                 activateEventNotifiers();
611             } else {
612                 // nothing todo so break
613                 break;
614             }
615             retVal = true;
616         }
617 
618         // still nothing - wait for message or signalled objects
619         canWait = (!retVal
620                    && !d->interrupt.loadRelaxed()
621                    && flags.testFlag(QEventLoop::WaitForMoreEvents)
622                    && threadData->canWaitLocked());
623         if (canWait) {
624             emit aboutToBlock();
625             waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
626             emit awake();
627             if (waitRet - WAIT_OBJECT_0 < nCount) {
628                 activateEventNotifiers();
629                 retVal = true;
630             }
631         }
632     } while (canWait);
633 
634     return retVal;
635 }
636 
hasPendingEvents()637 bool QEventDispatcherWin32::hasPendingEvents()
638 {
639     MSG msg;
640     return qGlobalPostedEventsCount() || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
641 }
642 
registerSocketNotifier(QSocketNotifier * notifier)643 void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
644 {
645     Q_ASSERT(notifier);
646     int sockfd = notifier->socket();
647     int type = notifier->type();
648 #ifndef QT_NO_DEBUG
649     if (sockfd < 0) {
650         qWarning("QEventDispatcherWin32::registerSocketNotifier: invalid socket identifier");
651         return;
652     }
653     if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
654         qWarning("QEventDispatcherWin32: socket notifiers cannot be enabled from another thread");
655         return;
656     }
657 #endif
658 
659     Q_D(QEventDispatcherWin32);
660     QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
661     QSNDict *dict = sn_vec[type];
662 
663     if (QCoreApplication::closingDown()) // ### d->exitloop?
664         return; // after sn_cleanup, don't reinitialize.
665 
666     if (dict->contains(sockfd)) {
667         const char *t[] = { "Read", "Write", "Exception" };
668     /* Variable "socket" below is a function pointer. */
669         qWarning("QSocketNotifier: Multiple socket notifiers for "
670                  "same socket %d and type %s", sockfd, t[type]);
671     }
672 
673     createInternalHwnd();
674 
675     QSockNot *sn = new QSockNot;
676     sn->obj = notifier;
677     sn->fd  = sockfd;
678     dict->insert(sn->fd, sn);
679 
680     long event = 0;
681     if (d->sn_read.contains(sockfd))
682         event |= FD_READ | FD_CLOSE | FD_ACCEPT;
683     if (d->sn_write.contains(sockfd))
684         event |= FD_WRITE | FD_CONNECT;
685     if (d->sn_except.contains(sockfd))
686         event |= FD_OOB;
687 
688     QSFDict::iterator it = d->active_fd.find(sockfd);
689     if (it != d->active_fd.end()) {
690         QSockFd &sd = it.value();
691         if (sd.selected) {
692             d->doWsaAsyncSelect(sockfd, 0);
693             sd.selected = false;
694         }
695         sd.event |= event;
696     } else {
697         // Disable the events which could be implicitly re-enabled. Next activation
698         // of socket notifiers will reset the mask.
699         d->active_fd.insert(sockfd, QSockFd(event, FD_READ | FD_ACCEPT | FD_WRITE | FD_OOB));
700     }
701 
702     d->postActivateSocketNotifiers();
703 }
704 
unregisterSocketNotifier(QSocketNotifier * notifier)705 void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
706 {
707     Q_ASSERT(notifier);
708 #ifndef QT_NO_DEBUG
709     int sockfd = notifier->socket();
710     if (sockfd < 0) {
711         qWarning("QEventDispatcherWin32::unregisterSocketNotifier: invalid socket identifier");
712         return;
713     }
714     if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
715         qWarning("QEventDispatcherWin32: socket notifiers cannot be disabled from another thread");
716         return;
717     }
718 #endif
719     doUnregisterSocketNotifier(notifier);
720 }
721 
doUnregisterSocketNotifier(QSocketNotifier * notifier)722 void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier)
723 {
724     Q_D(QEventDispatcherWin32);
725     int type = notifier->type();
726     int sockfd = notifier->socket();
727     Q_ASSERT(sockfd >= 0);
728 
729     QSFDict::iterator it = d->active_fd.find(sockfd);
730     if (it != d->active_fd.end()) {
731         QSockFd &sd = it.value();
732         if (sd.selected)
733             d->doWsaAsyncSelect(sockfd, 0);
734         const long event[3] = { FD_READ | FD_CLOSE | FD_ACCEPT, FD_WRITE | FD_CONNECT, FD_OOB };
735         sd.event ^= event[type];
736         if (sd.event == 0) {
737             d->active_fd.erase(it);
738         } else if (sd.selected) {
739             sd.selected = false;
740             d->postActivateSocketNotifiers();
741         }
742     }
743 
744     QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
745     QSNDict *dict = sn_vec[type];
746     QSockNot *sn = dict->value(sockfd);
747     if (!sn)
748         return;
749 
750     dict->remove(sockfd);
751     delete sn;
752 }
753 
registerTimer(int timerId,int interval,Qt::TimerType timerType,QObject * object)754 void QEventDispatcherWin32::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object)
755 {
756 #ifndef QT_NO_DEBUG
757     if (timerId < 1 || interval < 0 || !object) {
758         qWarning("QEventDispatcherWin32::registerTimer: invalid arguments");
759         return;
760     }
761     if (object->thread() != thread() || thread() != QThread::currentThread()) {
762         qWarning("QEventDispatcherWin32::registerTimer: timers cannot be started from another thread");
763         return;
764     }
765 #endif
766 
767     Q_D(QEventDispatcherWin32);
768 
769     // exiting ... do not register new timers
770     // (QCoreApplication::closingDown() is set too late to be used here)
771     if (d->closingDown)
772         return;
773 
774     WinTimerInfo *t = new WinTimerInfo;
775     t->dispatcher = this;
776     t->timerId  = timerId;
777     t->interval = interval;
778     t->timerType = timerType;
779     t->obj  = object;
780     t->inTimerEvent = false;
781     t->fastTimerId = 0;
782 
783     if (d->internalHwnd)
784         d->registerTimer(t);
785 
786     d->timerVec.append(t);                      // store in timer vector
787     d->timerDict.insert(t->timerId, t);          // store timers in dict
788 }
789 
unregisterTimer(int timerId)790 bool QEventDispatcherWin32::unregisterTimer(int timerId)
791 {
792 #ifndef QT_NO_DEBUG
793     if (timerId < 1) {
794         qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument");
795         return false;
796     }
797     if (thread() != QThread::currentThread()) {
798         qWarning("QEventDispatcherWin32::unregisterTimer: timers cannot be stopped from another thread");
799         return false;
800     }
801 #endif
802 
803     Q_D(QEventDispatcherWin32);
804     if (d->timerVec.isEmpty() || timerId <= 0)
805         return false;
806 
807     WinTimerInfo *t = d->timerDict.value(timerId);
808     if (!t)
809         return false;
810 
811     d->timerDict.remove(t->timerId);
812     d->timerVec.removeAll(t);
813     d->unregisterTimer(t);
814     return true;
815 }
816 
unregisterTimers(QObject * object)817 bool QEventDispatcherWin32::unregisterTimers(QObject *object)
818 {
819 #ifndef QT_NO_DEBUG
820     if (!object) {
821         qWarning("QEventDispatcherWin32::unregisterTimers: invalid argument");
822         return false;
823     }
824     if (object->thread() != thread() || thread() != QThread::currentThread()) {
825         qWarning("QEventDispatcherWin32::unregisterTimers: timers cannot be stopped from another thread");
826         return false;
827     }
828 #endif
829 
830     Q_D(QEventDispatcherWin32);
831     if (d->timerVec.isEmpty())
832         return false;
833     WinTimerInfo *t;
834     for (int i=0; i<d->timerVec.size(); i++) {
835         t = d->timerVec.at(i);
836         if (t && t->obj == object) {                // object found
837             d->timerDict.remove(t->timerId);
838             d->timerVec.removeAt(i);
839             d->unregisterTimer(t);
840             --i;
841         }
842     }
843     return true;
844 }
845 
846 QList<QEventDispatcherWin32::TimerInfo>
registeredTimers(QObject * object) const847 QEventDispatcherWin32::registeredTimers(QObject *object) const
848 {
849 #ifndef QT_NO_DEBUG
850     if (!object) {
851         qWarning("QEventDispatcherWin32:registeredTimers: invalid argument");
852         return QList<TimerInfo>();
853     }
854 #endif
855 
856     Q_D(const QEventDispatcherWin32);
857     QList<TimerInfo> list;
858     for (const WinTimerInfo *t : qAsConst(d->timerVec)) {
859         if (t && t->obj == object)
860             list << TimerInfo(t->timerId, t->interval, t->timerType);
861     }
862     return list;
863 }
864 
registerEventNotifier(QWinEventNotifier * notifier)865 bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier)
866 {
867     Q_ASSERT(notifier);
868 #ifndef QT_NO_DEBUG
869     if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
870         qWarning("QEventDispatcherWin32: event notifiers cannot be enabled from another thread");
871         return false;
872     }
873 #endif
874 
875     Q_D(QEventDispatcherWin32);
876 
877     if (d->winEventNotifierList.contains(notifier))
878         return true;
879 
880     d->winEventNotifierList.append(notifier);
881     d->winEventNotifierListModified = true;
882 
883     if (!d->winEventNotifierActivatedEvent)
884         d->winEventNotifierActivatedEvent = CreateEvent(0, TRUE, FALSE, nullptr);
885 
886     return QWinEventNotifierPrivate::get(notifier)->registerWaitObject();
887 }
888 
unregisterEventNotifier(QWinEventNotifier * notifier)889 void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier)
890 {
891     Q_ASSERT(notifier);
892 #ifndef QT_NO_DEBUG
893     if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
894         qWarning("QEventDispatcherWin32: event notifiers cannot be disabled from another thread");
895         return;
896     }
897 #endif
898     doUnregisterEventNotifier(notifier);
899 }
900 
doUnregisterEventNotifier(QWinEventNotifier * notifier)901 void QEventDispatcherWin32::doUnregisterEventNotifier(QWinEventNotifier *notifier)
902 {
903     Q_D(QEventDispatcherWin32);
904 
905     int i = d->winEventNotifierList.indexOf(notifier);
906     if (i == -1)
907         return;
908     d->winEventNotifierList.takeAt(i);
909     d->winEventNotifierListModified = true;
910     QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
911     if (nd->waitHandle)
912         nd->unregisterWaitObject();
913 }
914 
activateEventNotifiers()915 void QEventDispatcherWin32::activateEventNotifiers()
916 {
917     Q_D(QEventDispatcherWin32);
918     ResetEvent(d->winEventNotifierActivatedEvent);
919 
920     // Activate signaled notifiers. Our winEventNotifierList can be modified in activation slots.
921     do {
922         d->winEventNotifierListModified = false;
923         for (int i = 0; i < d->winEventNotifierList.count(); ++i) {
924             QWinEventNotifier *notifier = d->winEventNotifierList.at(i);
925             QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
926             if (nd->signaledCount.loadRelaxed() != 0) {
927                 --nd->signaledCount;
928                 nd->unregisterWaitObject();
929                 d->activateEventNotifier(notifier);
930             }
931         }
932     } while (d->winEventNotifierListModified);
933 
934     // Re-register the remaining activated notifiers.
935     for (int i = 0; i < d->winEventNotifierList.count(); ++i) {
936         QWinEventNotifier *notifier = d->winEventNotifierList.at(i);
937         QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
938         if (!nd->waitHandle)
939             nd->registerWaitObject();
940     }
941 }
942 
remainingTime(int timerId)943 int QEventDispatcherWin32::remainingTime(int timerId)
944 {
945 #ifndef QT_NO_DEBUG
946     if (timerId < 1) {
947         qWarning("QEventDispatcherWin32::remainingTime: invalid argument");
948         return -1;
949     }
950 #endif
951 
952     Q_D(QEventDispatcherWin32);
953 
954     if (d->timerVec.isEmpty())
955         return -1;
956 
957     quint64 currentTime = qt_msectime();
958 
959     for (const WinTimerInfo *t : qAsConst(d->timerVec)) {
960         if (t && t->timerId == timerId) {
961             // timer found, return time to wait
962 
963             if (d->internalHwnd)
964                 return t->timeout > currentTime ? t->timeout - currentTime : 0;
965             else
966                 return t->interval;
967         }
968     }
969 
970 #ifndef QT_NO_DEBUG
971     qWarning("QEventDispatcherWin32::remainingTime: timer id %d not found", timerId);
972 #endif
973 
974     return -1;
975 }
976 
wakeUp()977 void QEventDispatcherWin32::wakeUp()
978 {
979     Q_D(QEventDispatcherWin32);
980     if (d->internalHwnd && d->wakeUps.testAndSetAcquire(0, 1)) {
981         // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending
982         if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0))
983             qErrnoWarning("QEventDispatcherWin32::wakeUp: Failed to post a message");
984     }
985 }
986 
interrupt()987 void QEventDispatcherWin32::interrupt()
988 {
989     Q_D(QEventDispatcherWin32);
990     d->interrupt.storeRelaxed(true);
991     wakeUp();
992 }
993 
flush()994 void QEventDispatcherWin32::flush()
995 { }
996 
startingUp()997 void QEventDispatcherWin32::startingUp()
998 { }
999 
closingDown()1000 void QEventDispatcherWin32::closingDown()
1001 {
1002     Q_D(QEventDispatcherWin32);
1003 
1004     // clean up any socketnotifiers
1005     while (!d->sn_read.isEmpty())
1006         doUnregisterSocketNotifier((*(d->sn_read.begin()))->obj);
1007     while (!d->sn_write.isEmpty())
1008         doUnregisterSocketNotifier((*(d->sn_write.begin()))->obj);
1009     while (!d->sn_except.isEmpty())
1010         doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj);
1011     Q_ASSERT(d->active_fd.isEmpty());
1012 
1013     // clean up any eventnotifiers
1014     while (!d->winEventNotifierList.isEmpty())
1015         doUnregisterEventNotifier(d->winEventNotifierList.first());
1016 
1017     // clean up any timers
1018     for (int i = 0; i < d->timerVec.count(); ++i)
1019         d->unregisterTimer(d->timerVec.at(i));
1020     d->timerVec.clear();
1021     d->timerDict.clear();
1022 
1023     d->closingDown = true;
1024 
1025     if (d->getMessageHook)
1026         UnhookWindowsHookEx(d->getMessageHook);
1027     d->getMessageHook = 0;
1028 
1029     if (d->sendPostedEventsTimerId != 0)
1030         KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
1031     d->sendPostedEventsTimerId = 0;
1032 }
1033 
event(QEvent * e)1034 bool QEventDispatcherWin32::event(QEvent *e)
1035 {
1036     Q_D(QEventDispatcherWin32);
1037     switch (e->type()) {
1038     case QEvent::ZeroTimerEvent: {
1039         QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e);
1040         WinTimerInfo *t = d->timerDict.value(zte->timerId());
1041         if (t) {
1042             t->inTimerEvent = true;
1043 
1044             QTimerEvent te(zte->timerId());
1045             QCoreApplication::sendEvent(t->obj, &te);
1046 
1047             // timer could have been removed
1048             if (t->timerId == -1) {
1049                 delete t;
1050             } else {
1051                 if (t->interval == 0 && t->inTimerEvent) {
1052                     // post the next zero timer event as long as the timer was not restarted
1053                     QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId()));
1054                 }
1055 
1056                 t->inTimerEvent = false;
1057             }
1058         }
1059         return true;
1060     }
1061     case QEvent::Timer:
1062         d->sendTimerEvent(static_cast<const QTimerEvent*>(e)->timerId());
1063         break;
1064     default:
1065         break;
1066     }
1067     return QAbstractEventDispatcher::event(e);
1068 }
1069 
sendPostedEvents()1070 void QEventDispatcherWin32::sendPostedEvents()
1071 {
1072     Q_D(QEventDispatcherWin32);
1073 
1074     if (d->sendPostedEventsTimerId != 0)
1075         KillTimer(d->internalHwnd, d->sendPostedEventsTimerId);
1076     d->sendPostedEventsTimerId = 0;
1077 
1078     // Allow posting WM_QT_SENDPOSTEDEVENTS message.
1079     d->wakeUps.storeRelaxed(0);
1080 
1081     QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData.loadRelaxed());
1082 }
1083 
internalHwnd()1084 HWND QEventDispatcherWin32::internalHwnd()
1085 {
1086     Q_D(QEventDispatcherWin32);
1087     createInternalHwnd();
1088     return d->internalHwnd;
1089 }
1090 
1091 QT_END_NAMESPACE
1092