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