--- a/Quail-redux.pro Fri Aug 30 09:43:23 2013 +0100
+++ b/Quail-redux.pro Wed Sep 18 11:56:17 2013 +0100
@@ -1,163 +1,169 @@
-DEFINES += APP_DISPLAY_VERSION=\\\"0.1.0\\\"
-DEFINES += APP_MAJOR_VERSION=\\\"0\\\"
-VERSION = $${APP_DISPLAY_VERSION}
-CONFIG = qt warn_on debug
-DEFINES += APP_NAME=\\\"Quail\\\"
-DEFINES += QUAIL_PREFS_ROOT=\\\"/quail\\\"
-DEFINES += UI_ID=\\\"quail\\\"
-# Check that we have the repository folder
-exists(.hg):DEFINES += BUILDREVISION=\\\"$$system( hg parent --template \"{node}\")\\\"
-else:DEFINES += BUILDREVISION=\\\"NOTBUILTFROMSOURCEREPOSITORY\\\"
-# DEFINES += BUILDTIME=\\\"$$system('time/T')\\\"
-# DEFINES += BUILDDATE=\\\"$$system('echo %date%')\\\"
-# DEFINES += BUILDTIME=\\\"$$system(date '+%H:%M.%s')\\\"
-# DEFINES += BUILDDATE=\\\"$$system(date '+%d/%m/%y')\\\"
-greaterThan(QT_MAJOR_VERSION, 4) {
- src/QuailAccountBox.h \
- src/QuailAccountEditor.h \
- src/QuailAccountsWindow.h \
- src/QuailBListWindow.h \
- src/QuailConnectionMeter.h \
- src/QuailConvButton.h \
- src/QuailConvWindow.h \
- src/QuailDebugWindow.h \
- src/QuailImageUtils.h \
- src/QuailInputDialog.h \
- src/QuailMainWindow.h \
- src/QuailMultiLineEdit.h \
- src/QuailPrefsDialog.h \
- src/QuailProtocolBox.h \
- src/QuailProtocolUtils.h \
- src/QuailConvDisplay.h \
- src/QuailStatusSelector.h \
- src/QuailAccountBox.cpp \
- src/QuailAccountEditor.cpp \
- src/QuailAccountsWindow.cpp \
- src/QuailBListWindow.cpp \
- src/QuailBuddyList.cpp \
- src/QuailConnectionMeter.cpp \
- src/QuailConvButton.cpp \
- src/QuailConvWindow.cpp \
- src/QuailDebugWindow.cpp \
- src/QuailEventLoop.cpp \
- src/QuailImageUtils.cpp \
- src/QuailInputDialog.cpp \
- src/QuailMainWindow.cpp \
- src/QuailMultiLineEdit.cpp \
- src/QuailPrefsDialog.cpp \
- src/QuailProtocolBox.cpp \
- src/QuailProtocolUtils.cpp \
- src/QuailTabWidget.cpp \
- src/QuailConvDisplay.cpp \
- src/QuailStatusSelector.cpp \
- CONFIG += link_pkgconfig
- PKGCONFIG += purple glib-2.0 gmodule-2.0
- INCLUDEPATH += /cygdrive/c/dev/win32-dev/gtk_2_0-2.14/include/glib-2.0 \
- /cygdrive/c/dev/win32-dev/gtk_2_0-2.14/include/glib-2.0/include \
- /cygdrive/c/dev/pidgin-main \
- c:/dev/win32-dev/gtk_2_0-2.14/include/glib-2.0 \
- C:/dev/win32-dev/gtk_2_0-2.14/lib/glib-2.0/include
- LIBS += -L"C:/dev/win32-dev/gtk-2.24.10/lib"
- LIBS += -L"C:/dev/pidgin-main/libpurple"
- LIBS += -L"C:/Qt/4.8.5/lib"
- LIBS += -llibpurple -lglib-2.0 -lgmodule-2.0
- android/AndroidManifest.xml \
- android/res/layout/splash.xml \
- android/res/values/libs.xml \
- android/res/values/strings.xml \
- android/res/values-de/strings.xml \
- android/res/values-el/strings.xml \
- android/res/values-es/strings.xml \
- android/res/values-et/strings.xml \
- android/res/values-fa/strings.xml \
- android/res/values-fr/strings.xml \
- android/res/values-id/strings.xml \
- android/res/values-it/strings.xml \
- android/res/values-ja/strings.xml \
- android/res/values-ms/strings.xml \
- android/res/values-nb/strings.xml \
- android/res/values-nl/strings.xml \
- android/res/values-pl/strings.xml \
- android/res/values-pt-rBR/strings.xml \
- android/res/values-ro/strings.xml \
- android/res/values-rs/strings.xml \
- android/res/values-ru/strings.xml \
- android/res/values-zh-rCN/strings.xml \
- android/res/values-zh-rTW/strings.xml \
- android/src/org/kde/necessitas/ministro/IMinistro.aidl \
- android/src/org/kde/necessitas/ministro/IMinistroCallback.aidl \
- android/src/org/qtproject/qt5/android/bindings/QtActivity.java \
- android/src/org/qtproject/qt5/android/bindings/QtApplication.java \
+DEFINES += APP_DISPLAY_VERSION=\\\"0.1.0\\\" +DEFINES += APP_MAJOR_VERSION=\\\"0\\\" +VERSION = $${APP_DISPLAY_VERSION} +DEFINES += APP_NAME=\\\"Quail\\\" +DEFINES += QUAIL_PREFS_ROOT=\\\"/quail\\\" +DEFINES += UI_ID=\\\"quail\\\" +# Check that we have the repository folder +exists(.hg):DEFINES += BUILDREVISION=\\\"$$system( hg parent --template \"{node}\")\\\" +else:DEFINES += BUILDREVISION=\\\"NOTBUILTFROMSOURCEREPOSITORY\\\" +# DEFINES += BUILDTIME=\\\"$$system('time/T')\\\" +# DEFINES += BUILDDATE=\\\"$$system('echo %date%')\\\" +# DEFINES += BUILDTIME=\\\"$$system(date '+%H:%M.%s')\\\" +# DEFINES += BUILDDATE=\\\"$$system(date '+%d/%m/%y')\\\" +greaterThan(QT_MAJOR_VERSION, 4) { + QT -= multimediawidgets +CONFIG = qt warn_on debug_and_release + CONFIG += link_pkgconfig + PKGCONFIG += purple glib-2.0 gmodule-2.0 + HEADERS += src/QuailWinGlibEventLoop.h + SOURCES += src/QuailWinGlibEventLoop.cpp + LIBS += -llibpurple -lglib-2.0 -lgmodule-2.0 + INCLUDEPATH += $(LIBPURPLE_ROOT)/../win32-dev/gtk_2_0-2.14/include/glib-2.0 + INCLUDEPATH += $(LIBPURPLE_ROOT)/../win32-dev/gtk_2_0-2.14/include/glib-2.0/include + INCLUDEPATH += $(LIBPURPLE_ROOT)/../win32-dev/gtk_2_0-2.14/lib/glib-2.0/include + INCLUDEPATH += $(LIBPURPLE_ROOT) + INCLUDEPATH += $(QTDIR)/include + LIBS += -L"$(LIBPURPLE_ROOT)/../win32-dev/gtk-2.24.10/lib" + LIBS += -L"$(LIBPURPLE_ROOT)/libpurple" + LIBS += -L"$(QTDIR)/lib" + src/QuailAccountBox.h \ + src/QuailAccountEditor.h \ + src/QuailAccountsWindow.h \ + src/QuailBListWindow.h \ + src/QuailConnectionMeter.h \ + src/QuailConvButton.h \ + src/QuailConvWindow.h \ + src/QuailDebugWindow.h \ + src/QuailImageUtils.h \ + src/QuailInputDialog.h \ + src/QuailMainWindow.h \ + src/QuailMultiLineEdit.h \ + src/QuailPrefsDialog.h \ + src/QuailProtocolBox.h \ + src/QuailProtocolUtils.h \ + src/QuailConvDisplay.h \ + src/QuailStatusSelector.h \ + src/QuailAccountBox.cpp \ + src/QuailAccountEditor.cpp \ + src/QuailAccountsWindow.cpp \ + src/QuailBListWindow.cpp \ + src/QuailBuddyList.cpp \ + src/QuailConnectionMeter.cpp \ + src/QuailConvButton.cpp \ + src/QuailConvWindow.cpp \ + src/QuailDebugWindow.cpp \ + src/QuailEventLoop.cpp \ + src/QuailImageUtils.cpp \ + src/QuailInputDialog.cpp \ + src/QuailMainWindow.cpp \ + src/QuailMultiLineEdit.cpp \ + src/QuailPrefsDialog.cpp \ + src/QuailProtocolBox.cpp \ + src/QuailProtocolUtils.cpp \ + src/QuailTabWidget.cpp \ + src/QuailConvDisplay.cpp \ + src/QuailStatusSelector.cpp \ + android/AndroidManifest.xml \ + android/res/layout/splash.xml \ + android/res/values/libs.xml \ + android/res/values/strings.xml \ + android/res/values-de/strings.xml \ + android/res/values-el/strings.xml \ + android/res/values-es/strings.xml \ + android/res/values-et/strings.xml \ + android/res/values-fa/strings.xml \ + android/res/values-fr/strings.xml \ + android/res/values-id/strings.xml \ + android/res/values-it/strings.xml \ + android/res/values-ja/strings.xml \ + android/res/values-ms/strings.xml \ + android/res/values-nb/strings.xml \ + android/res/values-nl/strings.xml \ + android/res/values-pl/strings.xml \ + android/res/values-pt-rBR/strings.xml \ + android/res/values-ro/strings.xml \ + android/res/values-rs/strings.xml \ + android/res/values-ru/strings.xml \ + android/res/values-zh-rCN/strings.xml \ + android/res/values-zh-rTW/strings.xml \ + android/src/org/kde/necessitas/ministro/IMinistro.aidl \ + android/src/org/kde/necessitas/ministro/IMinistroCallback.aidl \ + android/src/org/qtproject/qt5/android/bindings/QtActivity.java \ + android/src/org/qtproject/qt5/android/bindings/QtApplication.java \ --- a/quail.qrc Fri Aug 30 09:43:23 2013 +0100
+++ b/quail.qrc Wed Sep 18 11:56:17 2013 +0100
@@ -3,7 +3,6 @@
<file>data/images/status/activebuddy.png</file>
<file>data/images/status/admin.png</file>
<file>data/images/status/aol.png</file>
- <file>data/images/status/away.png</file>
<file>data/images/status/dnd.png</file>
<file>data/images/status/extendedaway.png</file>
<file>data/images/status/female.png</file>
--- a/src/QuailBuddyList.cpp Fri Aug 30 09:43:23 2013 +0100
+++ b/src/QuailBuddyList.cpp Wed Sep 18 11:56:17 2013 +0100
@@ -543,6 +543,7 @@
setColumnWidth(0, BUDDY_ICON_SIZE);
setColumnWidth(1, this->width() - (BUDDY_ICON_SIZE *4));
setColumnWidth(2, BUDDY_ICON_SIZE);
+ qDebug() << "QQuailBuddyList::resizeEvent.end"; --- a/src/QuailEventLoop.cpp Fri Aug 30 09:43:23 2013 +0100
+++ b/src/QuailEventLoop.cpp Wed Sep 18 11:56:17 2013 +0100
@@ -25,13 +25,13 @@
- QQuailInputNotifier *notifier;
+ QQuailInputNotifier *notifier; @@ -41,17 +41,17 @@
static QMap<guint, QQuailSourceInfo*> m_sources;
QQuailTimer::QQuailTimer(guint sourceId, GSourceFunc func, gpointer data)
- : QTimer(), sourceId(sourceId), func(func), userData(data)
+ : QTimer(), sourceId(sourceId), func(func), userData(data) - connect(this, SIGNAL(timeout()),
+ connect(this, SIGNAL(timeout()),
- qQuailSourceRemove(sourceId);
+ qQuailSourceRemove(sourceId); QQuailInputNotifier::QQuailInputNotifier(int fd,
@@ -59,50 +59,50 @@
PurpleInputFunction func,
: QObject(), func(func), userData(userData), readNotifier(NULL),
//qDebug() << "QQuailInputNotifier::QQuailInputNotifier";
if (cond & PURPLE_INPUT_READ)
//qDebug() << "QQuailInputNotifier::QQuailInputNotifier::READ";
- readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read);
+ readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read); - connect(readNotifier, SIGNAL(activated(int)),
- this, SLOT(ioInvoke(int)));
+ connect(readNotifier, SIGNAL(activated(int)), + this, SLOT(ioInvoke(int))); if (cond & PURPLE_INPUT_WRITE)
//qDebug() << "QQuailInputNotifier::QQuailInputNotifier::WRITE";
- writeNotifier = new QSocketNotifier(fd, QSocketNotifier::Write);
+ writeNotifier = new QSocketNotifier(fd, QSocketNotifier::Write); - connect(writeNotifier, SIGNAL(activated(int)),
- this, SLOT(ioInvoke(int)));
+ connect(writeNotifier, SIGNAL(activated(int)), + this, SLOT(ioInvoke(int))); QQuailInputNotifier::~QQuailInputNotifier()
- if (readNotifier != NULL)
+ if (readNotifier != NULL) - if (writeNotifier != NULL)
+ if (writeNotifier != NULL) QQuailInputNotifier::ioInvoke(int fd)
//qDebug() << "QQuailInputNotifier::ioInvoke";
- if (readNotifier != NULL)
+ if (readNotifier != NULL) cond |= PURPLE_INPUT_READ;
- if (writeNotifier != NULL)
+ if (writeNotifier != NULL) cond |= PURPLE_INPUT_WRITE;
- func(userData, fd, (PurpleInputCondition)cond);
+ func(userData, fd, (PurpleInputCondition)cond); @@ -110,25 +110,25 @@
qQuailTimeoutAdd(guint interval, GSourceFunc func, gpointer data)
//qDebug() << "QQuailInputNotifier::qQuailTimeoutAdd";
- QQuailSourceInfo *info = new QQuailSourceInfo;
+ QQuailSourceInfo *info = new QQuailSourceInfo; - info->handle = nextSourceId++;
+ info->handle = nextSourceId++; - info->timer = new QQuailTimer(info->handle, func, data);
- info->timer->start(interval);
+ info->timer = new QQuailTimer(info->handle, func, data); + info->timer->start(interval); m_sources.insert(info->handle, info);
qQuailTimeoutRemove(guint handle)
//qDebug() << "QQuailInputNotifier::qQuailTimeoutRemove";
- qQuailSourceRemove(handle);
+ qQuailSourceRemove(handle);
@@ -138,36 +138,36 @@
//qDebug() << "QQuailInputNotifier::qQuailInputAdd";
- QQuailSourceInfo *info = new QQuailSourceInfo;
+ QQuailSourceInfo *info = new QQuailSourceInfo; - info->handle = nextSourceId++;
+ info->handle = nextSourceId++; - info->notifier = new QQuailInputNotifier(fd, cond, func, userData);
+ info->notifier = new QQuailInputNotifier(fd, cond, func, userData); m_sources.insert(info->handle, info);
qQuailSourceRemove(guint handle)
//qDebug() << "QQuailInputNotifier::qQuailSourceRemove";
- QQuailSourceInfo *info;
+ QQuailSourceInfo *info; info = m_sources.value(handle);
m_sources.remove(handle);
- if (info->timer != NULL)
- else if (info->notifier != NULL)
+ if (info->timer != NULL) + else if (info->notifier != NULL)
@@ -203,5 +203,5 @@
qQuailGetEventLoopUiOps(void)
--- a/src/QuailEventLoop.h Fri Aug 30 09:43:23 2013 +0100
+++ b/src/QuailEventLoop.h Wed Sep 18 11:56:17 2013 +0100
@@ -27,41 +27,41 @@
#include <QSocketNotifier>
/* http://harmattan-dev.nokia.com/docs/library/html/qt4/qabstracteventdispatcher.html */
-#include <QAbstractEventDispatcher>
+//#include <QAbstractEventDispatcher> class QQuailTimer : public QTimer
- QQuailTimer(guint sourceId, GSourceFunc func, gpointer data);
+ QQuailTimer(guint sourceId, GSourceFunc func, gpointer data);
class QQuailInputNotifier : public QObject
- QQuailInputNotifier(int fd, PurpleInputCondition cond,
- PurpleInputFunction func, gpointer userData);
- ~QQuailInputNotifier();
+ QQuailInputNotifier(int fd, PurpleInputCondition cond, + PurpleInputFunction func, gpointer userData); + ~QQuailInputNotifier();
- PurpleInputCondition cond;
- PurpleInputFunction func;
- QSocketNotifier *readNotifier, *writeNotifier;
+ PurpleInputCondition cond; + PurpleInputFunction func; + QSocketNotifier *readNotifier, *writeNotifier; --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/QuailWinGlibEventLoop.cpp Wed Sep 18 11:56:17 2013 +0100
@@ -0,0 +1,1366 @@
+#include "QuailWinGlibEventLoop.h" +#include <QCoreApplication> +struct GPollFDWithQSocketNotifier + QSocketNotifier *socketNotifier; +struct GSocketNotifierSource + QList<GPollFDWithQSocketNotifier *> pollfds; +static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout) +static gboolean socketNotifierSourceCheck(GSource *source) + GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source); + for (int i = 0; !pending && i < src->pollfds.count(); ++i) { + GPollFDWithQSocketNotifier *p = src->pollfds.at(i); + if (p->pollfd.revents & G_IO_NVAL) { + // disable the invalid socket notifier + static const char *t[] = { "Read", "Write", "Exception" }; + qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...", + p->pollfd.fd, t[int(p->socketNotifier->type())]); + // ### note, modifies src->pollfds! + p->socketNotifier->setEnabled(false); + pending = ((p->pollfd.revents & p->pollfd.events) != 0); +static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpointer) + QEvent event(QEvent::SockAct); + GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source); + for (int i = 0; i < src->pollfds.count(); ++i) { + GPollFDWithQSocketNotifier *p = src->pollfds.at(i); + if ((p->pollfd.revents & p->pollfd.events) != 0) + QCoreApplication::sendEvent(p->socketNotifier, &event); + return true; // ??? don't remove, right? +static GSourceFuncs socketNotifierSourceFuncs = { + socketNotifierSourcePrepare, + socketNotifierSourceCheck, + socketNotifierSourceDispatch, + QTimerInfoList timerList; + QEventLoop::ProcessEventsFlags processEventsFlags; + bool runWithIdlePriority; +static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout) + timespec tv = { 0l, 0l }; + if (!(src->processEventsFlags & QEventLoop::X11ExcludeTimers) && src->timerList.timerWait(tv)) + *timeout = (tv.tv_sec * 1000) + ((tv.tv_nsec + 999999) / 1000 / 1000); + return (*timeout == 0); +static gboolean timerSourceCheckHelper(GTimerSource *src) + if (src->timerList.isEmpty() + || (src->processEventsFlags & QEventLoop::X11ExcludeTimers)) + if (src->timerList.updateCurrentTime() < src->timerList.first()->timeout) +static gboolean timerSourcePrepare(GSource *source, gint *timeout) + GTimerSource *src = reinterpret_cast<GTimerSource *>(source); + if (src->runWithIdlePriority) { + return timerSourcePrepareHelper(src, timeout); +static gboolean timerSourceCheck(GSource *source) + GTimerSource *src = reinterpret_cast<GTimerSource *>(source); + if (src->runWithIdlePriority) + return timerSourceCheckHelper(src); +static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer) + GTimerSource *timerSource = reinterpret_cast<GTimerSource *>(source); + if (timerSource->processEventsFlags & QEventLoop::X11ExcludeTimers) + timerSource->runWithIdlePriority = true; + (void) timerSource->timerList.activateTimers(); + return true; // ??? don't remove, right again? +static GSourceFuncs timerSourceFuncs = { + GTimerSource *timerSource; +static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout) + GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source); + GTimerSource *timerSource = idleTimerSource->timerSource; + if (!timerSource->runWithIdlePriority) { + // Yield to the normal priority timer source + return timerSourcePrepareHelper(timerSource, timeout); +static gboolean idleTimerSourceCheck(GSource *source) + GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source); + GTimerSource *timerSource = idleTimerSource->timerSource; + if (!timerSource->runWithIdlePriority) { + // Yield to the normal priority timer source + return timerSourceCheckHelper(timerSource); +static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer) + GTimerSource *timerSource = reinterpret_cast<GIdleTimerSource *>(source)->timerSource; + (void) timerSourceDispatch(&timerSource->source, 0, 0); +static GSourceFuncs idleTimerSourceFuncs = { + idleTimerSourcePrepare, + idleTimerSourceDispatch, + QAtomicInt serialNumber; + QuailEventDispatcherWinGlib *d; +static gboolean postEventSourcePrepare(GSource *s, gint *timeout) + QThreadData *data = QThreadData::current(); + const bool canWait = data->canWaitLocked(); + *timeout = canWait ? -1 : 0; + GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s); + || (source->serialNumber.load() != source->lastSerialNumber)); +static gboolean postEventSourceCheck(GSource *source) + return postEventSourcePrepare(source, 0); +static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer) + GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s); + source->lastSerialNumber = source->serialNumber.load(); + QCoreApplication::sendPostedEvents(); + source->d->runTimersOnceWithNormalPriority(); + return true; // i dunno, george... +static GSourceFuncs postEventSourceFuncs = { + postEventSourcePrepare, + postEventSourceDispatch, +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) +#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"); +QuailEventDispatcherWinGlib::QuailEventDispatcherWinGlib(GMainContext *context = 0, QObject parent = 0) + : mainContext(context), threadId(GetCurrentThreadId()), interruptFlag(false), internalHwnd(0), getMessageHook(0), + serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), wakeUps(0) +#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 32 + if (qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB")) { + static QBasicMutex mutex; + QMutexLocker locker(&mutex); + if (!g_thread_supported()) + g_main_context_ref(mainContext); + QCoreApplication *app = QCoreApplication::instance(); + if (app && QThread::currentThread() == app->thread()) { + mainContext = g_main_context_default(); + g_main_context_ref(mainContext); + mainContext = g_main_context_new(); +#if GLIB_CHECK_VERSION (2, 22, 0) + g_main_context_push_thread_default (mainContext); + // setup post event source + postEventSource = reinterpret_cast<GPostEventSource *>(g_source_new(&postEventSourceFuncs, + sizeof(GPostEventSource))); + postEventSource->serialNumber.store(1); + postEventSource->d = this; + g_source_set_can_recurse(&postEventSource->source, true); + g_source_attach(&postEventSource->source, mainContext); + // setup socketNotifierSource + reinterpret_cast<GSocketNotifierSource *>(g_source_new(&socketNotifierSourceFuncs, + sizeof(GSocketNotifierSource))); + (void) new (&socketNotifierSource->pollfds) QList<GPollFDWithQSocketNotifier *>(); + g_source_set_can_recurse(&socketNotifierSource->source, true); + g_source_attach(&socketNotifierSource->source, mainContext); + // setup normal and idle timer sources + timerSource = reinterpret_cast<GTimerSource *>(g_source_new(&timerSourceFuncs, + sizeof(GTimerSource))); + (void) new (&timerSource->timerList) QTimerInfoList(); + timerSource->processEventsFlags = QEventLoop::AllEvents; + timerSource->runWithIdlePriority = false; + g_source_set_can_recurse(&timerSource->source, true); + g_source_attach(&timerSource->source, mainContext); + idleTimerSource = reinterpret_cast<GIdleTimerSource *>(g_source_new(&idleTimerSourceFuncs, + sizeof(GIdleTimerSource))); + idleTimerSource->timerSource = timerSource; + g_source_set_can_recurse(&idleTimerSource->source, true); + g_source_set_priority(&idleTimerSource->source, G_PRIORITY_DEFAULT_IDLE); + g_source_attach(&idleTimerSource->source, mainContext); +void QuailEventDispatcherWinGlib::runTimersOnceWithNormalPriority() + timerSource->runWithIdlePriority = false; +QuailEventDispatcherWinGlib::~QuailEventDispatcherWinGlib() + DestroyWindow(internalHwnd); + QString className = QLatin1String("QuailEventDispatcherWinGlib_Internal_Widget") + QString::number(quintptr(qt_internal_proc)); + UnregisterClass((wchar_t*)className.utf16(), qWinAppInst()); +void QuailEventDispatcherWinGlib::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); + QuailEventDispatcherWinGlib *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()); + QuailEventDispatcherWinGlib *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 QuailEventDispatcherWinGlib::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 QuailEventDispatcherWinGlib::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 QuailEventDispatcherWinGlib::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 QuailEventDispatcherWinGlib::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() +bool QuailEventDispatcherWinGlib::processEvents(QEventLoop::ProcessEventsFlags flags) + Q_D(QuailEventDispatcherWinGlib); + d->interruptFlag = false; + bool seenWM_QT_SENDPOSTEDEVENTS = false; + bool needWM_QT_SENDPOSTEDEVENTS = false; + HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1]; + QVarLengthArray<MSG> processedTimers; + while (!d->interruptFlag) { + 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); + d->interruptFlag = true; +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); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/QuailWinGlibEventLoop.h Wed Sep 18 11:56:17 2013 +0100
@@ -0,0 +1,139 @@
+#ifndef QUAILWINGLIBEVENTLOOP_H +#define QUAILWINGLIBEVENTLOOP_H +#include "QtCore/qt_windows.h" +#include "QtCore/qcoreevent.h" +#include <QAbstractEventDispatcher> +typedef struct _GMainContext GMainContext; +class QWinEventNotifier; +class QuailEventDispatcherWinGlibPrivate; +LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); +struct GPostEventSource; +struct GSocketNotifierSource; +struct GIdleTimerSource; +typedef QHash<int, QSockNot *> QSNDict; +struct WinTimerInfo { // internal timer info + Qt::TimerType timerType; + quint64 timeout; // - when to actually fire + QObject *obj; // - object to receive events +class QZeroTimerEvent : public QTimerEvent + explicit inline QZeroTimerEvent(int timerId) + { t = QEvent::ZeroTimerEvent; } +typedef QList<WinTimerInfo*> WinTimerVec; // vector of TimerInfo structs +typedef QHash<int, WinTimerInfo*> WinTimerDict; // fast dict of timers +class QuailEventDispatcherWinGlib : public QAbstractEventDispatcher + void createInternalHwnd(); + explicit QuailEventDispatcherWinGlib(GMainContext *context = 0, QObject *parent = 0); + ~QuailEventDispatcherWinGlib(); + bool QT_ENSURE_STACK_ALIGNED_FOR_SSE processEvents(QEventLoop::ProcessEventsFlags flags); + bool hasPendingEvents(); + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object); + bool unregisterTimer(int timerId); + bool unregisterTimers(QObject *object); + QList<TimerInfo> registeredTimers(QObject *object) const; + bool registerEventNotifier(QWinEventNotifier *notifier); + void unregisterEventNotifier(QWinEventNotifier *notifier); + void activateEventNotifiers(); + int remainingTime(int timerId); + static bool versionSupported(); + GMainContext *mainContext; + GPostEventSource *postEventSource; + GSocketNotifierSource *socketNotifierSource; + GTimerSource *timerSource; + GIdleTimerSource *idleTimerSource; + void runTimersOnceWithNormalPriority(); + // internal window handle used for socketnotifiers/timers/etc + // for controlling when to send posted events + QAtomicInt serialNumber; + int lastSerialNumber, sendPostedEventsWindowsTimerId; + WinTimerDict timerDict; + void registerTimer(WinTimerInfo *t); + void unregisterTimer(WinTimerInfo *t); + void sendTimerEvent(int timerId); + void doWsaAsyncSelect(int socket); + QList<QWinEventNotifier *> winEventNotifierList; + void activateEventNotifier(QWinEventNotifier * wen); + QList<MSG> queuedUserInputEvents; + QList<MSG> queuedSocketEvents; + virtual void sendPostedEvents(); + friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); + friend LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int, WPARAM, LPARAM); +#endif // QUAILWINGLIBEVENTLOOP_H --- a/src/main.cpp Fri Aug 30 09:43:23 2013 +0100
+++ b/src/main.cpp Wed Sep 18 11:56:17 2013 +0100
@@ -19,12 +19,20 @@
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+#include "QuailWinGlibEventLoop.h" #include "QuailMainWindow.h"
int main(int argc, char *argv[])
+ QuailEventDispatcherWinGlib quailEventLoop; QApplication a(argc, argv);