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