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