--- a/src/QuailWinGlibEventLoop.cpp Fri Sep 13 13:58:43 2013 +0100
+++ b/src/QuailWinGlibEventLoop.cpp Fri Sep 13 14:11:27 2013 +0100
@@ -1,5 +1,1082 @@
#include "QuailWinGlibEventLoop.h"
-QuailWinGlibEventLoop::QuailWinGlibEventLoop()
+#include <QCoreApplication> +HINSTANCE qWinAppInst(); +extern uint qGlobalPostedEventsCount(); +#ifndef TIME_KILL_SYNCHRONOUS +# define TIME_KILL_SYNCHRONOUS 0x0100 +# define QS_RAWINPUT 0x0000 +# define QS_RAWINPUT 0x0400 +# define WM_TOUCH 0x0240 +# define WM_GESTURE 0x0119 +#ifndef WM_GESTURENOTIFY +# define WM_GESTURENOTIFY 0x011A +#endif // QT_NO_GESTURES + WM_QT_SOCKETNOTIFIER = WM_USER, + WM_QT_SENDPOSTEDEVENTS = WM_USER + 1, + SendPostedEventsWindowsTimerId = ~1u +QT_BEGIN_INCLUDE_NAMESPACE +QT_END_INCLUDE_NAMESPACE +// Asynchronous Winsocks ------------------------------------------ +QT_BEGIN_INCLUDE_NAMESPACE +QT_END_INCLUDE_NAMESPACE +//#define QCE_ASYNC_DEBUG + class SocketAsyncHandler; + class SocketAsyncHandler : public QThread + void select(SOCKET sock, HWND handle, unsigned int msg, long ev); + void removeSelect(SOCKET sock); + void safeRemove(SOCKET sock); + QMap<SOCKET, SockInfo> sockets; + SocketAsyncHandler::SocketAsyncHandler() + SocketAsyncHandler::~SocketAsyncHandler() + while (sockets.size() > 0) + removeSelect(sockets.begin().key()); + void SocketAsyncHandler::removeSelect(SOCKET sock) + if (!sockets.contains(sock)) + void SocketAsyncHandler::safeRemove(SOCKET sock) + QMutexLocker locker(&mutex); + void SocketAsyncHandler::select(SOCKET sock, HWND handle, unsigned int msg, long ev) + QMutexLocker locker(&mutex); + if (sockets.contains(sock)) + sockets.insert(sock, info); + void SocketAsyncHandler::run() + while (!supposedToDie && sockets.isEmpty()) { + // Copy current items to reduce lock time + // and to be able to use SendMessage + QMap<SOCKET, SockInfo> currentSockets = sockets; + fd_set readS, writeS, exS; + for (QMap<SOCKET, SockInfo>::iterator it = currentSockets.begin(); it != currentSockets.end(); ++it) { + const SockInfo &info = it.value(); + maxFd = qMax(maxFd, socket); + if ((info.ev & FD_READ) || (info.ev & FD_CLOSE) || (info.ev & FD_ACCEPT)) + FD_SET(socket, &readS); + if ((info.ev & FD_WRITE)|| (info.ev & FD_CONNECT)) + FD_SET(socket, &writeS); + timeout.tv_usec = 50000; + int result = ::select(maxFd + 1, &readS, &writeS, &exS, &timeout); + for (QMap<SOCKET, SockInfo>::const_iterator it = currentSockets.constBegin(); + it != currentSockets.constEnd(); ++it) { + if (FD_ISSET(sock, &readS)) + ret = SendMessage(handle, tmpMsg, sock, FD_READ); + if (FD_ISSET(sock, &writeS)) + ret = SendMessage(handle, tmpMsg, sock, FD_WRITE); + if (FD_ISSET(sock, &exS)) + ret = SendMessage(handle, tmpMsg, sock, FD_OOB); + else if (result == 0) { //timeout + qDebug(" WSAAsync select timeout"); + } else if (result < 0) { // SocketError + // This might happen because of two reasons + // 1. We already closed a socket in between the copy and the select + // and thus select() returns an error + // 2. Something is really wrong, then + // ### Loop on all descriptors, try to select and remove the + qWarning("WSAAsync select error %d", WSAGetLastError()); +Q_GLOBAL_STATIC(SocketAsyncHandler, qt_async_handler) +int WSAAsyncSelect(SOCKET sock, HWND handle, unsigned int msg, long ev) + if (sock == 0 || handle == 0 || handle == INVALID_HANDLE_VALUE) { + WSASetLastError(WSAEINVAL); + if (msg == 0 && ev == 0) + qt_async_handler()->safeRemove(sock); + qt_async_handler()->select(sock, handle, msg, ev); + qt_async_handler()->start(QThread::LowPriority); +int WSAAsyncSelect(SOCKET, HWND, unsigned int, long) +class QuailEventDispatcherWinGlibPrivate; +#if !defined(DWORD_PTR) && !defined(Q_OS_WIN64) +typedef MMRESULT(WINAPI *ptimeSetEvent)(UINT, UINT, LPTIMECALLBACK, DWORD_PTR, UINT); +typedef MMRESULT(WINAPI *ptimeKillEvent)(UINT); +static ptimeSetEvent qtimeSetEvent = 0; +static ptimeKillEvent qtimeKillEvent = 0; +LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); +static void resolveTimerAPI() + static bool triedResolve = false; + QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve)); +#if !defined(Q_OS_WINCE) +# if defined(_MSC_VER) && _MSC_VER >= 1700 + if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8) { + qtimeSetEvent = (ptimeSetEvent)QSystemLibrary::resolve(QLatin1String("winmm"), "timeSetEvent"); + qtimeKillEvent = (ptimeKillEvent)QSystemLibrary::resolve(QLatin1String("winmm"), "timeKillEvent"); + qtimeSetEvent = (ptimeSetEvent)QSystemLibrary::resolve(QLatin1String("Mmtimer"), "timeSetEvent"); + qtimeKillEvent = (ptimeKillEvent)QSystemLibrary::resolve(QLatin1String("Mmtimer"), "timeKillEvent"); +QuailEventDispatcherWinGliPrivateb::QuailEventDispatcherWinGlibPrivate() + : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0), getMessageHook(0), + serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), wakeUps(0) +QuailEventDispatcherWinGlibPrivate::~QuailEventDispatcherWinGlibPrivate() + DestroyWindow(internalHwnd); + QString className = QLatin1String("QuailEventDispatcherWinGlib_Internal_Widget") + QString::number(quintptr(qt_internal_proc)); + UnregisterClass((wchar_t*)className.utf16(), qWinAppInst()); +void QuailEventDispatcherWinGlibPrivate::activateEventNotifier(QWinEventNotifier * wen) + QEvent event(QEvent::WinEventAct); + QCoreApplication::sendEvent(wen, &event); +// This function is called by a workerthread +void WINAPI QT_WIN_CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/) + if (!timerId) // sanity check + WinTimerInfo *t = (WinTimerInfo*)user; + QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId)); +LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) + if (message == WM_NCCREATE) + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); + if (message == WM_TIMER) + } else if (dispatcher->filterNativeEvent(QByteArrayLiteral("windows_dispatcher_MSG"), &msg, &result)) { + QuailEventDispatcherWinGlib *q = (QuailEventDispatcherWinGlib *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + QuailEventDispatcherWinGlib *q = (QuailEventDispatcherWinGlib *) GetWindowLong(hwnd, GWL_USERDATA); + QuailEventDispatcherWinGlibPrivate *d = 0; + if (message == WM_QT_SOCKETNOTIFIER) { + // socket notifier message + switch (WSAGETSELECTEVENT(lp)) { + QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read }; + QSNDict *dict = sn_vec[type]; + QSockNot *sn = dict ? dict->value(wp) : 0; + QEvent event(QEvent::SockAct); + QCoreApplication::sendEvent(sn->obj, &event); + QEvent event(QEvent::SockClose); + QCoreApplication::sendEvent(sn->obj, &event); + } else if (message == WM_QT_SENDPOSTEDEVENTS + // we also use a Windows timer to send posted events when the message queue is full + || (message == WM_TIMER + && d->sendPostedEventsWindowsTimerId != 0 + && wp == (uint)d->sendPostedEventsWindowsTimerId)) { + const int localSerialNumber = d->serialNumber.load(); + if (localSerialNumber != d->lastSerialNumber) { + d->lastSerialNumber = localSerialNumber; + } else if (message == WM_TIMER) { + return DefWindowProc(hwnd, message, wp, lp); +LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) + QuailEventDispatcherWinGlib *q = qobject_cast<QuailEventDispatcherWinGlib *>(QAbstractEventDispatcher::instance()); + QuailEventDispatcherWinGlibPrivate *d = q->d_func(); + const int localSerialNumber = d->serialNumber.load(); + if (HIWORD(GetQueueStatus(QS_TIMER | QS_INPUT | QS_RAWINPUT)) == 0) { + // no more input or timer events in the message queue, we can allow posted events to be sent normally now + if (d->sendPostedEventsWindowsTimerId != 0) { + // stop the timer to send posted events, since we now allow the WM_QT_SENDPOSTEDEVENTS message + KillTimer(d->internalHwnd, d->sendPostedEventsWindowsTimerId); + d->sendPostedEventsWindowsTimerId = 0; + (void) d->wakeUps.fetchAndStoreRelease(0); + if (localSerialNumber != d->lastSerialNumber + // if this message IS the one that triggers sendPostedEvents(), no need to post it again + && (msg->hwnd != d->internalHwnd + || msg->message != WM_QT_SENDPOSTEDEVENTS)) { + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); + } else if (d->sendPostedEventsWindowsTimerId == 0 + && localSerialNumber != d->lastSerialNumber) { + // start a special timer to continue delivering posted events while + // there are still input and timer messages in the message queue + d->sendPostedEventsWindowsTimerId = SetTimer(d->internalHwnd, + SendPostedEventsWindowsTimerId, + 0, // we specify zero, but Windows uses USER_TIMER_MINIMUM + // we don't check the return value of SetTimer()... if creating the timer failed, there's little + // we can do. we just have to accept that posted events will be starved + return CallNextHookEx(0, code, wp, lp); +static HWND qt_create_internal_window(const QuailEventDispatcherWinGlib *eventDispatcher) + // make sure that multiple Qt's can coexist in the same process + QString className = QLatin1String("QuailEventDispatcherWinGlib_Internal_Widget") + QString::number(quintptr(qt_internal_proc)); + wc.lpfnWndProc = qt_internal_proc; + wc.hInstance = qWinAppInst(); + wc.lpszMenuName = NULL; + wc.lpszClassName = reinterpret_cast<const wchar_t *> (className.utf16()); + HWND parent = HWND_MESSAGE; + HWND wnd = CreateWindow(wc.lpszClassName, // classname + wc.lpszClassName, // window name + 0, 0, 0, 0, // geometry + qWinAppInst(), // application + 0); // windows creation data. + qWarning("QEventDispatcher: Failed to create QuailEventDispatcherWinGlib internal window: %d\n", (int)GetLastError()); + SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher); + SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher); +void QuailEventDispatcherWinGlibPrivate::registerTimer(WinTimerInfo *t) + Q_ASSERT(internalHwnd); + Q_Q(QuailEventDispatcherWinGlib); + uint interval = t->interval; + // optimization for single-shot-zero-timer + QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); + } else if ((interval < 20u || t->timerType == Qt::PreciseTimer) && qtimeSetEvent) { + ok = t->fastTimerId = qtimeSetEvent(interval, 1, qt_fast_timer_proc, (DWORD_PTR)t, + TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS); + } else if (interval >= 20000u || t->timerType == Qt::VeryCoarseTimer) { + // round the interval, VeryCoarseTimers only have full second accuracy + interval = ((interval + 500)) / 1000 * 1000; + // user normal timers for (Very)CoarseTimers, or if no more multimedia timers available + ok = SetTimer(internalHwnd, t->timerId, interval, 0); + t->timeout = qt_msectime() + interval; + qErrnoWarning("QuailEventDispatcherWinGlib::registerTimer: Failed to create a timer"); +void QuailEventDispatcherWinGlibPrivate::unregisterTimer(WinTimerInfo *t) + if (t->interval == 0) { + QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId); + } else if (t->fastTimerId != 0) { + qtimeKillEvent(t->fastTimerId); + QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId); + } else if (internalHwnd) { + KillTimer(internalHwnd, t->timerId); +void QuailEventDispatcherWinGlibPrivate::sendTimerEvent(int timerId) + WinTimerInfo *t = timerDict.value(timerId); + if (t && !t->inTimerEvent) { + // send event, but don't allow it to recurse + t->inTimerEvent = true; + QTimerEvent e(t->timerId); + QCoreApplication::sendEvent(t->obj, &e); + // timer could have been removed + t = timerDict.value(timerId); + t->inTimerEvent = false; +void QuailEventDispatcherWinGlibPrivate::doWsaAsyncSelect(int socket) + Q_ASSERT(internalHwnd); + if (sn_read.contains(socket)) + sn_event |= FD_READ | FD_CLOSE | FD_ACCEPT; + if (sn_write.contains(socket)) + sn_event |= FD_WRITE | FD_CONNECT; + if (sn_except.contains(socket)) + // BoundsChecker may emit a warning for WSAAsyncSelect when sn_event == 0 + // This is a BoundsChecker bug and not a Qt bug + WSAAsyncSelect(socket, internalHwnd, sn_event ? int(WM_QT_SOCKETNOTIFIER) : 0, sn_event); +void QuailEventDispatcherWinGlib::createInternalHwnd() + Q_D(QuailEventDispatcherWinGlib); + Q_ASSERT(!d->internalHwnd); + d->internalHwnd = qt_create_internal_window(this); + // setup GetMessage hook needed to drive our posted events + d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId()); + if (!d->getMessageHook) { + qFatal("Qt: INTERNALL ERROR: failed to install GetMessage hook"); + // register all socket notifiers + QList<int> sockets = (d->sn_read.keys().toSet() + + d->sn_write.keys().toSet() + + d->sn_except.keys().toSet()).toList(); + for (int i = 0; i < sockets.count(); ++i) + d->doWsaAsyncSelect(sockets.at(i)); + // start all normal timers + for (int i = 0; i < d->timerVec.count(); ++i) + d->registerTimer(d->timerVec.at(i)); + // trigger a call to sendPostedEvents() +QuailEventDispatcherWinGlib::QuailEventDispatcherWinGlib(QObject *parent) + : QAbstractEventDispatcher(*new QuailEventDispatcherWinGlibPrivate, parent) +QuailEventDispatcherWinGlib::QuailEventDispatcherWinGlib(QuailEventDispatcherWinGlibPrivate &dd, QObject *parent) + : QAbstractEventDispatcher(dd, parent) +QuailEventDispatcherWinGlib::~QuailEventDispatcherWinGlib() +bool QuailEventDispatcherWinGlib::processEvents(QEventLoop::ProcessEventsFlags flags) + Q_D(QuailEventDispatcherWinGlib); + bool seenWM_QT_SENDPOSTEDEVENTS = false; + bool needWM_QT_SENDPOSTEDEVENTS = false; + HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1]; + QVarLengthArray<MSG> processedTimers; + while (!d->interrupt) { + DWORD nCount = d->winEventNotifierList.count(); + Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); + if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) { + // process queued user input events + msg = d->queuedUserInputEvents.takeFirst(); + } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) { + // process queued socket events + msg = d->queuedSocketEvents.takeFirst(); + haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE); + if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents) + && ((msg.message >= WM_KEYFIRST + && msg.message <= WM_KEYLAST) + || (msg.message >= WM_MOUSEFIRST + && msg.message <= WM_MOUSELAST) + || msg.message == WM_MOUSEWHEEL + || msg.message == WM_MOUSEHWHEEL + || msg.message == WM_TOUCH + || msg.message == WM_GESTURE + || msg.message == WM_GESTURENOTIFY + || msg.message == WM_CLOSE)) { + // queue user input events for later processing + d->queuedUserInputEvents.append(msg); + if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers) + && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) { + // queue socket events for later processing + d->queuedSocketEvents.append(msg); + // no message - check for signalled objects + for (int i=0; i<(int)nCount; i++) + pHandles[i] = d->winEventNotifierList.at(i)->handle(); + waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE); + if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) { + // a new message has arrived, process it + // WinCE doesn't support hooks at all, so we have to call this by hand :( + (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg); + if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) { + if (seenWM_QT_SENDPOSTEDEVENTS) { + // when calling processEvents() "manually", we only want to send posted + needWM_QT_SENDPOSTEDEVENTS = true; + seenWM_QT_SENDPOSTEDEVENTS = true; + } else if (msg.message == WM_TIMER) { + // avoid live-lock by keeping track of the timers we've already sent + for (int i = 0; !found && i < processedTimers.count(); ++i) { + const MSG processed = processedTimers.constData()[i]; + found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam); + processedTimers.append(msg); + } else if (msg.message == WM_QUIT) { + if (QCoreApplication::instance()) + QCoreApplication::instance()->quit(); + if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) { + TranslateMessage(&msg); + } else if (waitRet - WAIT_OBJECT_0 < nCount) { + d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); + // nothing todo so break + // still nothing - wait for message or signalled objects + && (flags & QEventLoop::WaitForMoreEvents)); + DWORD nCount = d->winEventNotifierList.count(); + Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); + for (int i=0; i<(int)nCount; i++) + pHandles[i] = d->winEventNotifierList.at(i)->handle(); + waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + if (waitRet - WAIT_OBJECT_0 < nCount) { + d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); + if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) { + // when called "manually", always send posted events + if (needWM_QT_SENDPOSTEDEVENTS) + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); +bool QuailEventDispatcherWinGlib::hasPendingEvents() + return qGlobalPostedEventsCount() || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); +void QuailEventDispatcherWinGlib::registerSocketNotifier(QSocketNotifier *notifier) + int sockfd = notifier->socket(); + int type = notifier->type(); + qWarning("QSocketNotifier: Internal error"); + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); + Q_D(QuailEventDispatcherWinGlib); + QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; + QSNDict *dict = sn_vec[type]; + if (QCoreApplication::closingDown()) // ### d->exitloop? + return; // after sn_cleanup, don't reinitialize. + if (dict->contains(sockfd)) { + const char *t[] = { "Read", "Write", "Exception" }; + /* Variable "socket" below is a function pointer. */ + qWarning("QSocketNotifier: Multiple socket notifiers for " + "same socket %d and type %s", sockfd, t[type]); + QSockNot *sn = new QSockNot; + dict->insert(sn->fd, sn); + d->doWsaAsyncSelect(sockfd); +void QuailEventDispatcherWinGlib::unregisterSocketNotifier(QSocketNotifier *notifier) + int sockfd = notifier->socket(); + int type = notifier->type(); + qWarning("QSocketNotifier: Internal error"); + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); + Q_D(QuailEventDispatcherWinGlib); + QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; + QSNDict *dict = sn_vec[type]; + QSockNot *sn = dict->value(sockfd); + d->doWsaAsyncSelect(sockfd); +void QuailEventDispatcherWinGlib::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) + if (timerId < 1 || interval < 0 || !object) { + qWarning("QuailEventDispatcherWinGlib::registerTimer: invalid arguments"); + } else if (object->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QObject::startTimer: timers cannot be started from another thread"); + Q_D(QuailEventDispatcherWinGlib); + WinTimerInfo *t = new WinTimerInfo; + t->interval = interval; + t->timerType = timerType; + t->inTimerEvent = false; + d->timerVec.append(t); // store in timer vector + d->timerDict.insert(t->timerId, t); // store timers in dict +bool QuailEventDispatcherWinGlib::unregisterTimer(int timerId) + qWarning("QuailEventDispatcherWinGlib::unregisterTimer: invalid argument"); + QThread *currentThread = QThread::currentThread(); + if (thread() != currentThread) { + qWarning("QObject::killTimer: timers cannot be stopped from another thread"); + Q_D(QuailEventDispatcherWinGlib); + if (d->timerVec.isEmpty() || timerId <= 0) + WinTimerInfo *t = d->timerDict.value(timerId); + d->timerDict.remove(t->timerId); + d->timerVec.removeAll(t); +bool QuailEventDispatcherWinGlib::unregisterTimers(QObject *object) + qWarning("QuailEventDispatcherWinGlib::unregisterTimers: invalid argument"); + QThread *currentThread = QThread::currentThread(); + if (object->thread() != thread() || thread() != currentThread) { + qWarning("QObject::killTimers: timers cannot be stopped from another thread"); + Q_D(QuailEventDispatcherWinGlib); + if (d->timerVec.isEmpty()) + register WinTimerInfo *t; + for (int i=0; i<d->timerVec.size(); i++) { + if (t && t->obj == object) { // object found + d->timerDict.remove(t->timerId); + d->timerVec.removeAt(i); +QList<QuailEventDispatcherWinGlib::TimerInfo> +QuailEventDispatcherWinGlib::registeredTimers(QObject *object) const + qWarning("QuailEventDispatcherWinGlib:registeredTimers: invalid argument"); + return QList<TimerInfo>(); + Q_D(const QuailEventDispatcherWinGlib); + for (int i = 0; i < d->timerVec.size(); ++i) { + const WinTimerInfo *t = d->timerVec.at(i); + if (t && t->obj == object) + list << TimerInfo(t->timerId, t->interval, t->timerType); +bool QuailEventDispatcherWinGlib::registerEventNotifier(QWinEventNotifier *notifier) + qWarning("QWinEventNotifier: Internal error"); + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QWinEventNotifier: event notifiers cannot be enabled from another thread"); + Q_D(QuailEventDispatcherWinGlib); + if (d->winEventNotifierList.contains(notifier)) + if (d->winEventNotifierList.count() >= MAXIMUM_WAIT_OBJECTS - 2) { + qWarning("QWinEventNotifier: Cannot have more than %d enabled at one time", MAXIMUM_WAIT_OBJECTS - 2); + d->winEventNotifierList.append(notifier); +void QuailEventDispatcherWinGlib::unregisterEventNotifier(QWinEventNotifier *notifier) + qWarning("QWinEventNotifier: Internal error"); + } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { + qWarning("QWinEventNotifier: event notifiers cannot be disabled from another thread"); + Q_D(QuailEventDispatcherWinGlib); + int i = d->winEventNotifierList.indexOf(notifier); + d->winEventNotifierList.takeAt(i); +void QuailEventDispatcherWinGlib::activateEventNotifiers() + Q_D(QuailEventDispatcherWinGlib); + //### this could break if events are removed/added in the activation + for (int i=0; i<d->winEventNotifierList.count(); i++) { +#if !defined(Q_OS_WINCE) + if (WaitForSingleObjectEx(d->winEventNotifierList.at(i)->handle(), 0, TRUE) == WAIT_OBJECT_0) + d->activateEventNotifier(d->winEventNotifierList.at(i)); + if (WaitForSingleObject(d->winEventNotifierList.at(i)->handle(), 0) == WAIT_OBJECT_0) + d->activateEventNotifier(d->winEventNotifierList.at(i)); +int QuailEventDispatcherWinGlib::remainingTime(int timerId) + qWarning("QuailEventDispatcherWinGlib::remainingTime: invalid argument"); + Q_D(QuailEventDispatcherWinGlib); + if (d->timerVec.isEmpty()) + quint64 currentTime = qt_msectime(); + register WinTimerInfo *t; + for (int i=0; i<d->timerVec.size(); i++) { + if (t && t->timerId == timerId) { // timer found + if (currentTime < t->timeout) { + return t->timeout - currentTime; + qWarning("QuailEventDispatcherWinGlib::remainingTime: timer id %d not found", timerId); +void QuailEventDispatcherWinGlib::wakeUp() + Q_D(QuailEventDispatcherWinGlib); + if (d->internalHwnd && d->wakeUps.testAndSetAcquire(0, 1)) { + // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending + PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); +void QuailEventDispatcherWinGlib::interrupt() + Q_D(QuailEventDispatcherWinGlib); +void QuailEventDispatcherWinGlib::flush() +void QuailEventDispatcherWinGlib::startingUp() +void QuailEventDispatcherWinGlib::closingDown() + Q_D(QuailEventDispatcherWinGlib); + // clean up any socketnotifiers + while (!d->sn_read.isEmpty()) + unregisterSocketNotifier((*(d->sn_read.begin()))->obj); + while (!d->sn_write.isEmpty()) + unregisterSocketNotifier((*(d->sn_write.begin()))->obj); + while (!d->sn_except.isEmpty()) + unregisterSocketNotifier((*(d->sn_except.begin()))->obj); + for (int i = 0; i < d->timerVec.count(); ++i) + d->unregisterTimer(d->timerVec.at(i)); + UnhookWindowsHookEx(d->getMessageHook); +bool QuailEventDispatcherWinGlib::event(QEvent *e) + Q_D(QuailEventDispatcherWinGlib); + if (e->type() == QEvent::ZeroTimerEvent) { + QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e); + WinTimerInfo *t = d->timerDict.value(zte->timerId()); + t->inTimerEvent = true; + QTimerEvent te(zte->timerId()); + QCoreApplication::sendEvent(t->obj, &te); + t = d->timerDict.value(zte->timerId()); + if (t->interval == 0 && t->inTimerEvent) { + // post the next zero timer event as long as the timer was not restarted + QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId())); + t->inTimerEvent = false; + } else if (e->type() == QEvent::Timer) { + QTimerEvent *te = static_cast<QTimerEvent*>(e); + d->sendTimerEvent(te->timerId()); + return QAbstractEventDispatcher::event(e); +void QuailEventDispatcherWinGlib::sendPostedEvents() + Q_D(QuailEventDispatcherWinGlib); + QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); --- a/src/QuailWinGlibEventLoop.h Fri Sep 13 13:58:43 2013 +0100
+++ b/src/QuailWinGlibEventLoop.h Fri Sep 13 14:11:27 2013 +0100
@@ -56,7 +56,7 @@
static bool versionSupported();
- QEventDispatcherWinGlib(QuailEventDispatcherWinGlibPrivate &dd, QObject *parent = 0);
+ QuailEventDispatcherWinGlib(QuailEventDispatcherWinGlibPrivate &dd, QObject *parent = 0); virtual void sendPostedEvents();
@@ -99,11 +99,11 @@
class Q_CORE_EXPORT QuailEventDispatcherWinGlibPrivate : public QAbstractEventDispatcherPrivate
- Q_DECLARE_PUBLIC(QEventDispatcherWinGlib)
+ Q_DECLARE_PUBLIC(QuailEventDispatcherWinGlib) - QEventDispatcherWinGlibPrivate();
- QEventDispatcherWinGlibPrivate(GMainContext *context = 0);
- ~QEventDispatcherWinGlibPrivate();
+ QuailEventDispatcherWinGlibPrivate(); + QuailEventDispatcherWinGlibPrivate(GMainContext *context = 0); + ~QuailEventDispatcherWinGlibPrivate(); GMainContext *mainContext;
GPostEventSource *postEventSource;