1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qeventdispatcher_win_p.h"
43 
44 #include "qcoreapplication.h"
45 #include "qhash.h"
46 #include <private/qsystemlibrary_p.h>
47 #include "qpair.h"
48 #include "qset.h"
49 #include "qsocketnotifier.h"
50 #include "qvarlengtharray.h"
51 #include "qwineventnotifier_p.h"
52 
53 #include "qabstracteventdispatcher_p.h"
54 #include "qcoreapplication_p.h"
55 #include <private/qthread_p.h>
56 
57 QT_BEGIN_NAMESPACE
58 
59 HINSTANCE qWinAppInst();
60 extern uint qGlobalPostedEventsCount();
61 
62 #ifndef TIME_KILL_SYNCHRONOUS
63 #  define TIME_KILL_SYNCHRONOUS 0x0100
64 #endif
65 
66 #ifndef QS_RAWINPUT
67 # ifdef Q_OS_WINCE
68 #  define QS_RAWINPUT 0x0000
69 # else
70 #  define QS_RAWINPUT 0x0400
71 # endif
72 #endif
73 
74 #ifndef WM_TOUCH
75 #  define WM_TOUCH 0x0240
76 #endif
77 #ifndef QT_NO_GESTURES
78 #ifndef WM_GESTURE
79 #  define WM_GESTURE 0x0119
80 #endif
81 #ifndef WM_GESTURENOTIFY
82 #  define WM_GESTURENOTIFY 0x011A
83 #endif
84 #endif // QT_NO_GESTURES
85 
86 enum {
87     WM_QT_SOCKETNOTIFIER = WM_USER,
88     WM_QT_SENDPOSTEDEVENTS = WM_USER + 1,
89     SendPostedEventsWindowsTimerId = ~1u
90 };
91 
92 #if defined(Q_OS_WINCE)
93 QT_BEGIN_INCLUDE_NAMESPACE
94 #include <winsock.h>
95 // Asynchronous Winsocks ------------------------------------------
96 #ifndef QT_NO_THREAD
97 #include <qthread.h>
98 #include <qmap.h>
99 #include <qmutex.h>
100 QT_END_INCLUDE_NAMESPACE
101 
102 //#define QCE_ASYNC_DEBUG
103 
104 namespace {
105     class SocketAsyncHandler;
106 
107     class SocketAsyncHandler : public QThread
108     {
109     public:
110         SocketAsyncHandler();
111         ~SocketAsyncHandler();
112         void run();
113         void select(SOCKET sock, HWND handle, unsigned int msg, long ev);
114         void removeSelect(SOCKET sock);
115         void safeRemove(SOCKET sock);
116     private:
117         struct SockInfo {
118             HWND handle;
119             unsigned int msg;
120             long ev;
121         };
122         QMap<SOCKET, SockInfo> sockets;
123         QMutex mutex;
124         QWaitCondition cond;
125         bool supposedToDie;
126     };
127 
SocketAsyncHandler()128     SocketAsyncHandler::SocketAsyncHandler()
129         : supposedToDie(false)
130     {
131     }
132 
~SocketAsyncHandler()133     SocketAsyncHandler::~SocketAsyncHandler()
134     {
135         mutex.lock();
136         supposedToDie = true;
137         mutex.unlock();
138         cond.wakeOne();
139         wait();
140         while (sockets.size() > 0)
141             removeSelect(sockets.begin().key());
142     }
143 
removeSelect(SOCKET sock)144     void SocketAsyncHandler::removeSelect(SOCKET sock)
145     {
146         if (!sockets.contains(sock))
147             return;
148         sockets.remove(sock);
149         return;
150     }
151 
safeRemove(SOCKET sock)152     void SocketAsyncHandler::safeRemove(SOCKET sock)
153     {
154         QMutexLocker locker(&mutex);
155         removeSelect(sock);
156     }
157 
select(SOCKET sock,HWND handle,unsigned int msg,long ev)158     void SocketAsyncHandler::select(SOCKET sock, HWND handle, unsigned int msg, long ev)
159     {
160         QMutexLocker locker(&mutex);
161 
162         if (sockets.contains(sock))
163             sockets.remove(sock);
164 
165         SockInfo info;
166         info.handle = handle;
167         info.msg = msg;
168         info.ev = ev;
169         sockets.insert(sock, info);
170         cond.wakeOne();
171     }
172 
run()173     void SocketAsyncHandler::run()
174     {
175         do {
176             mutex.lock();
177 
178             while (!supposedToDie && sockets.isEmpty()) {
179                 cond.wait(&mutex);
180             }
181 
182             if (supposedToDie) {
183                 mutex.unlock();
184                 break;
185             }
186 
187             // Copy current items to reduce lock time
188             // and to be able to use SendMessage
189             QMap<SOCKET, SockInfo> currentSockets = sockets;
190             mutex.unlock();
191 
192             fd_set readS, writeS, exS;
193             FD_ZERO(&readS);
194             FD_ZERO(&writeS);
195             FD_ZERO(&exS);
196 
197             int maxFd = 0;
198 
199             for (QMap<SOCKET, SockInfo>::iterator it = currentSockets.begin(); it != currentSockets.end(); ++it) {
200                 const SockInfo &info = it.value();
201                 int socket = it.key();
202                 maxFd = qMax(maxFd, socket);
203 
204                 if ((info.ev & FD_READ) || (info.ev & FD_CLOSE) || (info.ev & FD_ACCEPT))
205                     FD_SET(socket, &readS);
206                 if ((info.ev & FD_WRITE)|| (info.ev & FD_CONNECT))
207                     FD_SET(socket, &writeS);
208                 if (info.ev & FD_OOB)
209                     FD_SET(socket, &exS);
210             }
211 
212             timeval timeout;
213             timeout.tv_sec = 0;
214             timeout.tv_usec = 50000;
215             int result = ::select(maxFd + 1, &readS, &writeS, &exS, &timeout);
216             if (result > 0) {
217                 HWND handle;
218                 unsigned int tmpMsg;
219                 SOCKET sock;
220                 HRESULT ret;
221                 for (QMap<SOCKET, SockInfo>::const_iterator it = currentSockets.constBegin();
222                     it != currentSockets.constEnd(); ++it) {
223                         handle = (*it).handle;
224                         tmpMsg = (*it).msg;
225                         sock = it.key();
226                         if (FD_ISSET(sock, &readS))
227                             ret = SendMessage(handle, tmpMsg, sock, FD_READ);
228 
229                         if (FD_ISSET(sock, &writeS))
230                             ret = SendMessage(handle, tmpMsg, sock, FD_WRITE);
231 
232                         if (FD_ISSET(sock, &exS))
233                             ret = SendMessage(handle, tmpMsg, sock, FD_OOB);
234                 }
235             }
236 
237 #ifdef QCE_ASYNC_DEBUG
238             else if (result == 0) { //timeout
239                 qDebug("    WSAAsync select timeout");
240             } else if (result < 0) { // SocketError
241                 // This might happen because of two reasons
242                 // 1. We already closed a socket in between the copy and the select
243                 //    and thus select() returns an error
244                 // 2. Something is really wrong, then
245                 //    ### Loop on all descriptors, try to select and remove the
246                 //    ### broken one.
247                 qWarning("WSAAsync select error %d", WSAGetLastError());
248             }
249 #endif
250         } while(true);
251     }
252 } // namespace
253 
Q_GLOBAL_STATIC(SocketAsyncHandler,qt_async_handler)254 Q_GLOBAL_STATIC(SocketAsyncHandler, qt_async_handler)
255 
256 int WSAAsyncSelect(SOCKET sock, HWND handle, unsigned int msg, long ev)
257 {
258     if (sock == 0 || handle == 0 || handle == INVALID_HANDLE_VALUE) {
259         WSASetLastError(WSAEINVAL);
260         return SOCKET_ERROR;
261     }
262 
263     if (msg == 0 && ev == 0)
264         qt_async_handler()->safeRemove(sock);
265     else
266         qt_async_handler()->select(sock, handle, msg, ev);
267 
268     qt_async_handler()->start(QThread::LowPriority);
269     WSASetLastError(0);
270     return 0;
271 }
272 #else // QT_NO_THREAD
273 int WSAAsyncSelect(SOCKET, HWND, unsigned int, long)
274 {
275     return SOCKET_ERROR;
276 }
277 #endif
278 #endif // Q_OS_WINCE
279 
280 class QEventDispatcherWin32Private;
281 
282 struct QSockNot {
283     QSocketNotifier *obj;
284     int fd;
285 };
286 typedef QHash<int, QSockNot *> QSNDict;
287 
288 struct WinTimerInfo {                           // internal timer info
289     QObject *dispatcher;
290     int timerId;
291     int interval;
292     QObject *obj;                               // - object to receive events
293     bool inTimerEvent;
294     int fastTimerId;
295 };
296 
297 class QZeroTimerEvent : public QTimerEvent
298 {
299 public:
QZeroTimerEvent(int timerId)300     inline QZeroTimerEvent(int timerId)
301         : QTimerEvent(timerId)
302     { t = QEvent::ZeroTimerEvent; }
303 };
304 
305 typedef QList<WinTimerInfo*>  WinTimerVec;      // vector of TimerInfo structs
306 typedef QHash<int, WinTimerInfo*> WinTimerDict; // fast dict of timers
307 
308 #if !defined(DWORD_PTR) && !defined(Q_WS_WIN64)
309 #define DWORD_PTR DWORD
310 #endif
311 
312 typedef MMRESULT(WINAPI *ptimeSetEvent)(UINT, UINT, LPTIMECALLBACK, DWORD_PTR, UINT);
313 typedef MMRESULT(WINAPI *ptimeKillEvent)(UINT);
314 
315 static ptimeSetEvent qtimeSetEvent = 0;
316 static ptimeKillEvent qtimeKillEvent = 0;
317 
318 LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
319 
resolveTimerAPI()320 static void resolveTimerAPI()
321 {
322     static bool triedResolve = false;
323     if (!triedResolve) {
324 #ifdef Q_OS_WINCE
325         QSystemLibrary library(QLatin1String("Mmtimer"));
326 #else
327         QSystemLibrary library(QLatin1String("winmm"));
328 #endif
329         if (library.load()) {
330             qtimeSetEvent = (ptimeSetEvent)library.resolve("timeSetEvent");
331             qtimeKillEvent = (ptimeKillEvent)library.resolve("timeKillEvent");
332         }
333 
334         triedResolve = true;
335     }
336 }
337 
338 
339 class QEventDispatcherWin32Private : public QAbstractEventDispatcherPrivate
340 {
341     Q_DECLARE_PUBLIC(QEventDispatcherWin32)
342 public:
343     QEventDispatcherWin32Private();
344     ~QEventDispatcherWin32Private();
345 
346     DWORD threadId;
347 
348     bool interrupt;
349 
350     // internal window handle used for socketnotifiers/timers/etc
351     HWND internalHwnd;
352     HHOOK getMessageHook;
353 
354     // for controlling when to send posted events
355     QAtomicInt serialNumber;
356     int lastSerialNumber, sendPostedEventsWindowsTimerId;
357     QAtomicInt wakeUps;
358 
359     // timers
360     WinTimerVec timerVec;
361     WinTimerDict timerDict;
362     void registerTimer(WinTimerInfo *t);
363     void unregisterTimer(WinTimerInfo *t, bool closingDown = false);
364     void sendTimerEvent(int timerId);
365 
366     // socket notifiers
367     QSNDict sn_read;
368     QSNDict sn_write;
369     QSNDict sn_except;
370     void doWsaAsyncSelect(int socket);
371 
372     QList<QWinEventNotifier *> winEventNotifierList;
373     void activateEventNotifier(QWinEventNotifier * wen);
374 
375     QList<MSG> queuedUserInputEvents;
376     QList<MSG> queuedSocketEvents;
377 };
378 
QEventDispatcherWin32Private()379 QEventDispatcherWin32Private::QEventDispatcherWin32Private()
380     : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0), getMessageHook(0),
381       serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), wakeUps(0)
382 {
383     resolveTimerAPI();
384 }
385 
~QEventDispatcherWin32Private()386 QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
387 {
388     if (internalHwnd)
389         DestroyWindow(internalHwnd);
390     QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc));
391     UnregisterClass((wchar_t*)className.utf16(), qWinAppInst());
392 }
393 
activateEventNotifier(QWinEventNotifier * wen)394 void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen)
395 {
396     QEvent event(QEvent::WinEventAct);
397     QCoreApplication::sendEvent(wen, &event);
398 }
399 
400 // ### Qt 5: remove
winPeekMessage(MSG * msg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg)401 Q_CORE_EXPORT bool winPeekMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin,
402                      UINT wMsgFilterMax, UINT wRemoveMsg)
403 {
404     return PeekMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
405 }
406 
407 // ### Qt 5: remove
winPostMessage(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)408 Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
409 {
410     return PostMessage(hWnd, msg, wParam, lParam);
411 }
412 
413 // ### Qt 5: remove
winGetMessage(MSG * msg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax)414 Q_CORE_EXPORT bool winGetMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin,
415                      UINT wMsgFilterMax)
416 {
417     return GetMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax);
418 }
419 
420 // This function is called by a workerthread
qt_fast_timer_proc(uint timerId,uint,DWORD_PTR user,DWORD_PTR,DWORD_PTR)421 void WINAPI QT_WIN_CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/)
422 {
423     if (!timerId) // sanity check
424         return;
425     WinTimerInfo *t = (WinTimerInfo*)user;
426     Q_ASSERT(t);
427     QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId));
428 }
429 
qt_internal_proc(HWND hwnd,UINT message,WPARAM wp,LPARAM lp)430 LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
431 {
432     if (message == WM_NCCREATE)
433         return true;
434 
435     MSG msg;
436     msg.hwnd = hwnd;
437     msg.message = message;
438     msg.wParam = wp;
439     msg.lParam = lp;
440     QCoreApplication *app = QCoreApplication::instance();
441     long result;
442     if (!app) {
443         if (message == WM_TIMER)
444             KillTimer(hwnd, wp);
445         return 0;
446     } else if (app->filterEvent(&msg, &result)) {
447         return result;
448     }
449 
450 #ifdef GWLP_USERDATA
451     QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
452 #else
453     QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA);
454 #endif
455     QEventDispatcherWin32Private *d = 0;
456     if (q != 0)
457         d = q->d_func();
458 
459     if (message == WM_QT_SOCKETNOTIFIER) {
460         // socket notifier message
461         int type = -1;
462         switch (WSAGETSELECTEVENT(lp)) {
463         case FD_READ:
464         case FD_CLOSE:
465         case FD_ACCEPT:
466             type = 0;
467             break;
468         case FD_WRITE:
469         case FD_CONNECT:
470             type = 1;
471             break;
472         case FD_OOB:
473             type = 2;
474             break;
475         }
476         if (type >= 0) {
477             Q_ASSERT(d != 0);
478             QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
479             QSNDict *dict = sn_vec[type];
480 
481             QSockNot *sn = dict ? dict->value(wp) : 0;
482             if (sn) {
483                 QEvent event(QEvent::SockAct);
484                 QCoreApplication::sendEvent(sn->obj, &event);
485             }
486         }
487         return 0;
488     } else if (message == WM_QT_SENDPOSTEDEVENTS
489                // we also use a Windows timer to send posted events when the message queue is full
490                || (message == WM_TIMER
491                    && d->sendPostedEventsWindowsTimerId != 0
492                    && wp == (uint)d->sendPostedEventsWindowsTimerId)) {
493         int localSerialNumber = d->serialNumber;
494         if (localSerialNumber != d->lastSerialNumber) {
495             d->lastSerialNumber = localSerialNumber;
496             QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
497         }
498         return 0;
499     } else if (message == WM_TIMER) {
500         Q_ASSERT(d != 0);
501         d->sendTimerEvent(wp);
502         return 0;
503     }
504 
505     return DefWindowProc(hwnd, message, wp, lp);
506 }
507 
inputTimerMask()508 static inline UINT inputTimerMask()
509 {
510     UINT result = QS_TIMER | QS_INPUT | QS_RAWINPUT;
511     // QTBUG 28513, QTBUG-29097, QTBUG-29435: QS_TOUCH, QS_POINTER became part of
512     // QS_INPUT in Windows Kit 8. They should not be used when running on pre-Windows 8.
513 #if WINVER > 0x0601
514     if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8)
515         result &= ~(QS_TOUCH | QS_POINTER);
516 #endif // WINVER > 0x0601
517     return result;
518 }
519 
qt_GetMessageHook(int code,WPARAM wp,LPARAM lp)520 LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
521 {
522     if (wp == PM_REMOVE) {
523         QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
524         Q_ASSERT(q != 0);
525         if (q) {
526             MSG *msg = (MSG *) lp;
527             QEventDispatcherWin32Private *d = q->d_func();
528             int localSerialNumber = d->serialNumber;
529             static const UINT mask = inputTimerMask();
530             if (HIWORD(GetQueueStatus(mask)) == 0) {
531                 // no more input or timer events in the message queue, we can allow posted events to be sent normally now
532                 if (d->sendPostedEventsWindowsTimerId != 0) {
533                     // stop the timer to send posted events, since we now allow the WM_QT_SENDPOSTEDEVENTS message
534                     KillTimer(d->internalHwnd, d->sendPostedEventsWindowsTimerId);
535                     d->sendPostedEventsWindowsTimerId = 0;
536                 }
537                 (void) d->wakeUps.fetchAndStoreRelease(0);
538                 if (localSerialNumber != d->lastSerialNumber
539                     // if this message IS the one that triggers sendPostedEvents(), no need to post it again
540                     && (msg->hwnd != d->internalHwnd
541                         || msg->message != WM_QT_SENDPOSTEDEVENTS)) {
542                     PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
543                 }
544             } else if (d->sendPostedEventsWindowsTimerId == 0
545                        && localSerialNumber != d->lastSerialNumber) {
546                 // start a special timer to continue delivering posted events while
547                 // there are still input and timer messages in the message queue
548                 d->sendPostedEventsWindowsTimerId = SetTimer(d->internalHwnd,
549                                                              SendPostedEventsWindowsTimerId,
550                                                              0, // we specify zero, but Windows uses USER_TIMER_MINIMUM
551                                                              NULL);
552                 // we don't check the return value of SetTimer()... if creating the timer failed, there's little
553                 // we can do. we just have to accept that posted events will be starved
554             }
555         }
556     }
557 #ifdef Q_OS_WINCE
558     Q_UNUSED(code);
559     return 0;
560 #else
561     return CallNextHookEx(0, code, wp, lp);
562 #endif
563 }
564 
qt_create_internal_window(const QEventDispatcherWin32 * eventDispatcher)565 static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher)
566 {
567     // make sure that multiple Qt's can coexist in the same process
568     QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc));
569 
570     WNDCLASS wc;
571     wc.style = 0;
572     wc.lpfnWndProc = qt_internal_proc;
573     wc.cbClsExtra = 0;
574     wc.cbWndExtra = 0;
575     wc.hInstance = qWinAppInst();
576     wc.hIcon = 0;
577     wc.hCursor = 0;
578     wc.hbrBackground = 0;
579     wc.lpszMenuName = NULL;
580     wc.lpszClassName = reinterpret_cast<const wchar_t *> (className.utf16());
581 
582     RegisterClass(&wc);
583     HWND wnd = CreateWindow(wc.lpszClassName,  // classname
584                             wc.lpszClassName,  // window name
585                             0,                 // style
586                             0, 0, 0, 0,        // geometry
587                             0,                 // parent
588                             0,                 // menu handle
589                             qWinAppInst(),     // application
590                             0);                // windows creation data.
591 
592     if (!wnd) {
593         qWarning("QEventDispatcher: Failed to create QEventDispatcherWin32 internal window: %d\n", (int)GetLastError());
594     }
595 
596 #ifdef GWLP_USERDATA
597     SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher);
598 #else
599     SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher);
600 #endif
601 
602     return wnd;
603 }
604 
registerTimer(WinTimerInfo * t)605 void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
606 {
607     Q_ASSERT(internalHwnd);
608 
609     Q_Q(QEventDispatcherWin32);
610 
611     int ok = 0;
612     if (t->interval > 20 || !t->interval || !qtimeSetEvent) {
613         ok = 1;
614         if (!t->interval)  // optimization for single-shot-zero-timer
615             QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
616         else
617             ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);
618     } else {
619         ok = t->fastTimerId = qtimeSetEvent(t->interval, 1, qt_fast_timer_proc, (DWORD_PTR)t,
620                                             TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
621         if (ok == 0) { // fall back to normal timer if no more multimedia timers available
622             ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);
623         }
624     }
625 
626     if (ok == 0)
627         qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
628 }
629 
unregisterTimer(WinTimerInfo * t,bool closingDown)630 void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t, bool closingDown)
631 {
632     // mark timer as unused
633     if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent && !closingDown)
634         QAbstractEventDispatcherPrivate::releaseTimerId(t->timerId);
635 
636     if (t->interval == 0) {
637         QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
638     } else if (t->fastTimerId != 0) {
639         qtimeKillEvent(t->fastTimerId);
640         QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
641     } else if (internalHwnd) {
642         KillTimer(internalHwnd, t->timerId);
643     }
644     delete t;
645 }
646 
sendTimerEvent(int timerId)647 void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
648 {
649     WinTimerInfo *t = timerDict.value(timerId);
650     if (t && !t->inTimerEvent) {
651         // send event, but don't allow it to recurse
652         t->inTimerEvent = true;
653 
654         QTimerEvent e(t->timerId);
655         QCoreApplication::sendEvent(t->obj, &e);
656 
657         // timer could have been removed
658         t = timerDict.value(timerId);
659         if (t) {
660             t->inTimerEvent = false;
661         }
662     }
663 }
664 
doWsaAsyncSelect(int socket)665 void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket)
666 {
667     Q_ASSERT(internalHwnd);
668     int sn_event = 0;
669     if (sn_read.contains(socket))
670         sn_event |= FD_READ | FD_CLOSE | FD_ACCEPT;
671     if (sn_write.contains(socket))
672         sn_event |= FD_WRITE | FD_CONNECT;
673     if (sn_except.contains(socket))
674         sn_event |= FD_OOB;
675     // BoundsChecker may emit a warning for WSAAsyncSelect when sn_event == 0
676     // This is a BoundsChecker bug and not a Qt bug
677     WSAAsyncSelect(socket, internalHwnd, sn_event ? unsigned(WM_QT_SOCKETNOTIFIER) : unsigned(0), sn_event);
678 }
679 
createInternalHwnd()680 void QEventDispatcherWin32::createInternalHwnd()
681 {
682     Q_D(QEventDispatcherWin32);
683 
684     Q_ASSERT(!d->internalHwnd);
685     if (d->internalHwnd)
686         return;
687     d->internalHwnd = qt_create_internal_window(this);
688 
689 #ifndef Q_OS_WINCE
690     // setup GetMessage hook needed to drive our posted events
691     d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
692     if (!d->getMessageHook) {
693         qFatal("Qt: INTERNALL ERROR: failed to install GetMessage hook");
694     }
695 #endif
696 
697     // register all socket notifiers
698     QList<int> sockets = (d->sn_read.keys().toSet()
699                           + d->sn_write.keys().toSet()
700                           + d->sn_except.keys().toSet()).toList();
701     for (int i = 0; i < sockets.count(); ++i)
702         d->doWsaAsyncSelect(sockets.at(i));
703 
704     // start all normal timers
705     for (int i = 0; i < d->timerVec.count(); ++i)
706         d->registerTimer(d->timerVec.at(i));
707 
708     // trigger a call to sendPostedEvents()
709     wakeUp();
710 }
711 
QEventDispatcherWin32(QObject * parent)712 QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
713     : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent)
714 {
715 }
716 
~QEventDispatcherWin32()717 QEventDispatcherWin32::~QEventDispatcherWin32()
718 {
719 }
720 
processEvents(QEventLoop::ProcessEventsFlags flags)721 bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
722 {
723     Q_D(QEventDispatcherWin32);
724 
725     if (!d->internalHwnd)
726         createInternalHwnd();
727 
728     d->interrupt = false;
729     emit awake();
730 
731     bool canWait;
732     bool retVal = false;
733     bool seenWM_QT_SENDPOSTEDEVENTS = false;
734     bool needWM_QT_SENDPOSTEDEVENTS = false;
735     do {
736         DWORD waitRet = 0;
737         HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
738         QVarLengthArray<MSG> processedTimers;
739         while (!d->interrupt) {
740             DWORD nCount = d->winEventNotifierList.count();
741             Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
742 
743             MSG msg;
744             bool haveMessage;
745 
746             if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
747                 // process queued user input events
748                 haveMessage = true;
749                 msg = d->queuedUserInputEvents.takeFirst();
750             } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
751                 // process queued socket events
752                 haveMessage = true;
753                 msg = d->queuedSocketEvents.takeFirst();
754             } else {
755                 haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
756                 if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents)
757                     && ((msg.message >= WM_KEYFIRST
758                          && msg.message <= WM_KEYLAST)
759                         || (msg.message >= WM_MOUSEFIRST
760                             && msg.message <= WM_MOUSELAST)
761                         || msg.message == WM_MOUSEWHEEL
762                         || msg.message == WM_MOUSEHWHEEL
763                         || msg.message == WM_TOUCH
764 #ifndef QT_NO_GESTURES
765                         || msg.message == WM_GESTURE
766                         || msg.message == WM_GESTURENOTIFY
767 #endif
768                         || msg.message == WM_CLOSE)) {
769                     // queue user input events for later processing
770                     haveMessage = false;
771                     d->queuedUserInputEvents.append(msg);
772                 }
773                 if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)
774                     && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
775                     // queue socket events for later processing
776                     haveMessage = false;
777                     d->queuedSocketEvents.append(msg);
778                 }
779             }
780             if (!haveMessage) {
781                 // no message - check for signalled objects
782                 for (int i=0; i<(int)nCount; i++)
783                     pHandles[i] = d->winEventNotifierList.at(i)->handle();
784                 waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE);
785                 if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) {
786                     // a new message has arrived, process it
787                     continue;
788                 }
789             }
790             if (haveMessage) {
791 #ifdef Q_OS_WINCE
792                 // WinCE doesn't support hooks at all, so we have to call this by hand :(
793                 (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg);
794 #endif
795 
796                 if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
797                     if (seenWM_QT_SENDPOSTEDEVENTS) {
798                         // when calling processEvents() "manually", we only want to send posted
799                         // events once
800                         needWM_QT_SENDPOSTEDEVENTS = true;
801                         continue;
802                     }
803                     seenWM_QT_SENDPOSTEDEVENTS = true;
804                 } else if (msg.message == WM_TIMER) {
805                     // avoid live-lock by keeping track of the timers we've already sent
806                     bool found = false;
807                     for (int i = 0; !found && i < processedTimers.count(); ++i) {
808                         const MSG processed = processedTimers.constData()[i];
809                         found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
810                     }
811                     if (found)
812                         continue;
813                     processedTimers.append(msg);
814                 } else if (msg.message == WM_QUIT) {
815                     if (QCoreApplication::instance())
816                         QCoreApplication::instance()->quit();
817                     return false;
818                 }
819 
820                 if (!filterEvent(&msg)) {
821                     TranslateMessage(&msg);
822                     DispatchMessage(&msg);
823                 }
824             } else if (waitRet < WAIT_OBJECT_0 + nCount) {
825                 d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
826             } else {
827                 // nothing todo so break
828                 break;
829             }
830             retVal = true;
831         }
832 
833         // still nothing - wait for message or signalled objects
834         canWait = (!retVal
835                    && !d->interrupt
836                    && (flags & QEventLoop::WaitForMoreEvents));
837         if (canWait) {
838             DWORD nCount = d->winEventNotifierList.count();
839             Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
840             for (int i=0; i<(int)nCount; i++)
841                 pHandles[i] = d->winEventNotifierList.at(i)->handle();
842 
843             emit aboutToBlock();
844             waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
845             emit awake();
846             if (waitRet < WAIT_OBJECT_0 + nCount) {
847                 d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
848                 retVal = true;
849             }
850         }
851     } while (canWait);
852 
853     if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) {
854         // when called "manually", always send posted events
855         QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
856     }
857 
858     if (needWM_QT_SENDPOSTEDEVENTS)
859         PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
860 
861     return retVal;
862 }
863 
hasPendingEvents()864 bool QEventDispatcherWin32::hasPendingEvents()
865 {
866     MSG msg;
867     return qGlobalPostedEventsCount() || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
868 }
869 
registerSocketNotifier(QSocketNotifier * notifier)870 void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
871 {
872     Q_ASSERT(notifier);
873     int sockfd = notifier->socket();
874     int type = notifier->type();
875 #ifndef QT_NO_DEBUG
876     if (sockfd < 0) {
877         qWarning("QSocketNotifier: Internal error");
878         return;
879     } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
880         qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
881         return;
882     }
883 #endif
884 
885     Q_D(QEventDispatcherWin32);
886     QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
887     QSNDict *dict = sn_vec[type];
888 
889     if (QCoreApplication::closingDown()) // ### d->exitloop?
890         return; // after sn_cleanup, don't reinitialize.
891 
892     if (dict->contains(sockfd)) {
893         const char *t[] = { "Read", "Write", "Exception" };
894     /* Variable "socket" below is a function pointer. */
895         qWarning("QSocketNotifier: Multiple socket notifiers for "
896                  "same socket %d and type %s", sockfd, t[type]);
897     }
898 
899     QSockNot *sn = new QSockNot;
900     sn->obj = notifier;
901     sn->fd  = sockfd;
902     dict->insert(sn->fd, sn);
903 
904     if (d->internalHwnd)
905         d->doWsaAsyncSelect(sockfd);
906 }
907 
unregisterSocketNotifier(QSocketNotifier * notifier)908 void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
909 {
910     Q_ASSERT(notifier);
911     int sockfd = notifier->socket();
912     int type = notifier->type();
913 #ifndef QT_NO_DEBUG
914     if (sockfd < 0) {
915         qWarning("QSocketNotifier: Internal error");
916         return;
917     } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
918         qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
919         return;
920     }
921 #endif
922 
923     Q_D(QEventDispatcherWin32);
924     QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
925     QSNDict *dict = sn_vec[type];
926     QSockNot *sn = dict->value(sockfd);
927     if (!sn)
928         return;
929 
930     dict->remove(sockfd);
931     delete sn;
932 
933     if (d->internalHwnd)
934         d->doWsaAsyncSelect(sockfd);
935 }
936 
registerTimer(int timerId,int interval,QObject * object)937 void QEventDispatcherWin32::registerTimer(int timerId, int interval, QObject *object)
938 {
939     if (timerId < 1 || interval < 0 || !object) {
940         qWarning("QEventDispatcherWin32::registerTimer: invalid arguments");
941         return;
942     } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
943         qWarning("QObject::startTimer: timers cannot be started from another thread");
944         return;
945     }
946 
947     Q_D(QEventDispatcherWin32);
948 
949     register WinTimerInfo *t = new WinTimerInfo;
950     t->dispatcher = this;
951     t->timerId  = timerId;
952     t->interval = interval;
953     t->obj  = object;
954     t->inTimerEvent = false;
955     t->fastTimerId = 0;
956 
957     if (d->internalHwnd)
958         d->registerTimer(t);
959 
960     d->timerVec.append(t);                      // store in timer vector
961     d->timerDict.insert(t->timerId, t);          // store timers in dict
962 }
963 
unregisterTimer(int timerId)964 bool QEventDispatcherWin32::unregisterTimer(int timerId)
965 {
966     if (timerId < 1) {
967         qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument");
968         return false;
969     }
970     QThread *currentThread = QThread::currentThread();
971     if (thread() != currentThread) {
972         qWarning("QObject::killTimer: timers cannot be stopped from another thread");
973         return false;
974     }
975 
976     Q_D(QEventDispatcherWin32);
977     if (d->timerVec.isEmpty() || timerId <= 0)
978         return false;
979 
980     WinTimerInfo *t = d->timerDict.value(timerId);
981     if (!t)
982         return false;
983 
984     d->timerDict.remove(t->timerId);
985     d->timerVec.removeAll(t);
986     d->unregisterTimer(t);
987     return true;
988 }
989 
unregisterTimers(QObject * object)990 bool QEventDispatcherWin32::unregisterTimers(QObject *object)
991 {
992     if (!object) {
993         qWarning("QEventDispatcherWin32::unregisterTimers: invalid argument");
994         return false;
995     }
996     QThread *currentThread = QThread::currentThread();
997     if (object->thread() != thread() || thread() != currentThread) {
998         qWarning("QObject::killTimers: timers cannot be stopped from another thread");
999         return false;
1000     }
1001 
1002     Q_D(QEventDispatcherWin32);
1003     if (d->timerVec.isEmpty())
1004         return false;
1005     register WinTimerInfo *t;
1006     for (int i=0; i<d->timerVec.size(); i++) {
1007         t = d->timerVec.at(i);
1008         if (t && t->obj == object) {                // object found
1009             d->timerDict.remove(t->timerId);
1010             d->timerVec.removeAt(i);
1011             d->unregisterTimer(t);
1012             --i;
1013         }
1014     }
1015     return true;
1016 }
1017 
1018 QList<QEventDispatcherWin32::TimerInfo>
registeredTimers(QObject * object) const1019 QEventDispatcherWin32::registeredTimers(QObject *object) const
1020 {
1021     if (!object) {
1022         qWarning("QEventDispatcherWin32:registeredTimers: invalid argument");
1023         return QList<TimerInfo>();
1024     }
1025 
1026     Q_D(const QEventDispatcherWin32);
1027     QList<TimerInfo> list;
1028     for (int i = 0; i < d->timerVec.size(); ++i) {
1029         const WinTimerInfo *t = d->timerVec.at(i);
1030         if (t && t->obj == object)
1031             list << TimerInfo(t->timerId, t->interval);
1032     }
1033     return list;
1034 }
1035 
registerEventNotifier(QWinEventNotifier * notifier)1036 bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier)
1037 {
1038     if (!notifier) {
1039         qWarning("QWinEventNotifier: Internal error");
1040         return false;
1041     } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
1042         qWarning("QWinEventNotifier: event notifiers cannot be enabled from another thread");
1043         return false;
1044     }
1045 
1046     Q_D(QEventDispatcherWin32);
1047 
1048     if (d->winEventNotifierList.contains(notifier))
1049         return true;
1050 
1051     if (d->winEventNotifierList.count() >= MAXIMUM_WAIT_OBJECTS - 2) {
1052         qWarning("QWinEventNotifier: Cannot have more than %d enabled at one time", MAXIMUM_WAIT_OBJECTS - 2);
1053         return false;
1054     }
1055     d->winEventNotifierList.append(notifier);
1056     return true;
1057 }
1058 
unregisterEventNotifier(QWinEventNotifier * notifier)1059 void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier)
1060 {
1061     if (!notifier) {
1062         qWarning("QWinEventNotifier: Internal error");
1063         return;
1064     } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
1065         qWarning("QWinEventNotifier: event notifiers cannot be disabled from another thread");
1066         return;
1067     }
1068 
1069     Q_D(QEventDispatcherWin32);
1070 
1071     int i = d->winEventNotifierList.indexOf(notifier);
1072     if (i != -1)
1073         d->winEventNotifierList.takeAt(i);
1074 }
1075 
activateEventNotifiers()1076 void QEventDispatcherWin32::activateEventNotifiers()
1077 {
1078     Q_D(QEventDispatcherWin32);
1079     //### this could break if events are removed/added in the activation
1080     for (int i=0; i<d->winEventNotifierList.count(); i++) {
1081 #if !defined(Q_OS_WINCE)
1082         if (WaitForSingleObjectEx(d->winEventNotifierList.at(i)->handle(), 0, TRUE) == WAIT_OBJECT_0)
1083             d->activateEventNotifier(d->winEventNotifierList.at(i));
1084 #else
1085         if (WaitForSingleObject(d->winEventNotifierList.at(i)->handle(), 0) == WAIT_OBJECT_0)
1086             d->activateEventNotifier(d->winEventNotifierList.at(i));
1087 #endif
1088     }
1089 }
1090 
wakeUp()1091 void QEventDispatcherWin32::wakeUp()
1092 {
1093     Q_D(QEventDispatcherWin32);
1094     d->serialNumber.ref();
1095     if (d->internalHwnd && d->wakeUps.testAndSetAcquire(0, 1)) {
1096         // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending
1097         PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
1098     }
1099 }
1100 
interrupt()1101 void QEventDispatcherWin32::interrupt()
1102 {
1103     Q_D(QEventDispatcherWin32);
1104     d->interrupt = true;
1105     wakeUp();
1106 }
1107 
flush()1108 void QEventDispatcherWin32::flush()
1109 { }
1110 
startingUp()1111 void QEventDispatcherWin32::startingUp()
1112 { }
1113 
closingDown()1114 void QEventDispatcherWin32::closingDown()
1115 {
1116     Q_D(QEventDispatcherWin32);
1117 
1118     // clean up any socketnotifiers
1119     while (!d->sn_read.isEmpty())
1120         unregisterSocketNotifier((*(d->sn_read.begin()))->obj);
1121     while (!d->sn_write.isEmpty())
1122         unregisterSocketNotifier((*(d->sn_write.begin()))->obj);
1123     while (!d->sn_except.isEmpty())
1124         unregisterSocketNotifier((*(d->sn_except.begin()))->obj);
1125 
1126     // clean up any timers
1127     for (int i = 0; i < d->timerVec.count(); ++i)
1128         d->unregisterTimer(d->timerVec.at(i), true);
1129     d->timerVec.clear();
1130     d->timerDict.clear();
1131 
1132 #ifndef Q_OS_WINCE
1133     if (d->getMessageHook)
1134         UnhookWindowsHookEx(d->getMessageHook);
1135     d->getMessageHook = 0;
1136 #endif
1137 }
1138 
event(QEvent * e)1139 bool QEventDispatcherWin32::event(QEvent *e)
1140 {
1141     Q_D(QEventDispatcherWin32);
1142     if (e->type() == QEvent::ZeroTimerEvent) {
1143         QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e);
1144         WinTimerInfo *t = d->timerDict.value(zte->timerId());
1145         if (t) {
1146             t->inTimerEvent = true;
1147 
1148             QTimerEvent te(zte->timerId());
1149             QCoreApplication::sendEvent(t->obj, &te);
1150 
1151             t = d->timerDict.value(zte->timerId());
1152             if (t) {
1153                 if (t->interval == 0 && t->inTimerEvent) {
1154                     // post the next zero timer event as long as the timer was not restarted
1155                     QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId()));
1156                 }
1157 
1158                 t->inTimerEvent = false;
1159             }
1160         }
1161         return true;
1162     } else if (e->type() == QEvent::Timer) {
1163         QTimerEvent *te = static_cast<QTimerEvent*>(e);
1164         d->sendTimerEvent(te->timerId());
1165     }
1166     return QAbstractEventDispatcher::event(e);
1167 }
1168 
1169 QT_END_NAMESPACE
1170