pidgin/quail/quail-redux

Merge the new windows event loop

2013-09-18, Phil Hannent
1ef97abc822a
Merge the new windows event loop
--- a/.hgignore Fri Aug 30 09:43:23 2013 +0100
+++ b/.hgignore Wed Sep 18 11:56:17 2013 +0100
@@ -14,11 +14,11 @@
*.gz
.*.swp
.todo.*
-Makefile
+Makefile*
gaim
temp*
moc_*
-object_script.Quail
+object_script.Quail*
*.pdb
qrc_*.cpp
*~
--- 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\\\"
-
-TEMPLATE = app
-TARGET = Quail
-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\\\"
-
-#win32-g++ {
-# DEFINES += BUILDTIME=\\\"$$system('time/T')\\\"
-# DEFINES += BUILDDATE=\\\"$$system('echo %date%')\\\"
-#}
-#else {
-# DEFINES += BUILDTIME=\\\"$$system(date '+%H:%M.%s')\\\"
-# DEFINES += BUILDDATE=\\\"$$system(date '+%d/%m/%y')\\\"
-#}
-
-QT += core gui webkit
-greaterThan(QT_MAJOR_VERSION, 4) {
- message("Using QT5")
- DEFINES += USE_QT5
- QT += widgets
- QT += webkitwidgets
-}
-
-HEADERS = \
- src/QuailAccountBox.h \
- src/QuailAccountEditor.h \
- src/QuailAccountsWindow.h \
- src/QuailAction.h \
- src/QuailBListWindow.h \
- src/QuailBuddyList.h \
- src/QuailConnectionMeter.h \
- src/QuailConvButton.h \
- src/QuailConvWindow.h \
- src/QuailDebugWindow.h \
- src/QuailEventLoop.h \
- src/QuailDialogs.h \
- src/QuailImageUtils.h \
- src/QuailInputDialog.h \
- src/QuailMainWindow.h \
- src/QuailMultiLineEdit.h \
- src/QuailNotify.h \
- src/QuailPrefsDialog.h \
- src/QuailProtocolBox.h \
- src/QuailProtocolUtils.h \
- src/QuailRequest.h \
- src/QuailTabBar.h \
- src/QuailTabWidget.h \
- src/global.h \
- src/QuailConvDisplay.h \
- src/QuailStatusSelector.h \
- src/QuailBlistItem.h
-
-
-SOURCES = \
- 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/QuailDialogs.cpp \
- src/QuailEventLoop.cpp \
- src/QuailImageUtils.cpp \
- src/QuailInputDialog.cpp \
- src/QuailMainWindow.cpp \
- src/QuailMultiLineEdit.cpp \
- src/QuailNotify.cpp \
- src/QuailPrefsDialog.cpp \
- src/QuailProtocolBox.cpp \
- src/QuailProtocolUtils.cpp \
- src/QuailRequest.cpp \
- src/QuailTabBar.cpp \
- src/QuailTabWidget.cpp \
- src/main.cpp \
- src/QuailConvDisplay.cpp \
- src/QuailStatusSelector.cpp \
- src/QuailBlistItem.cpp
-
-
-DISTFILES = \
- AUTHORS \
- ChangeLog \
- NEWS \
- README \
- quail.png \
- make.sh \
- mkstuff.conf \
- mkipk.sh \
- mktarball.sh
-
-linux-g++* {
- message("Using unix")
- CONFIG += link_pkgconfig
- PKGCONFIG += purple glib-2.0 gmodule-2.0
-}
-
-win32-g++ {
- message("Using win32")
- 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/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"
-
- #RC_FILE = resource.rc
-
- LIBS += -llibpurple -lglib-2.0 -lgmodule-2.0
-}
-
-
-OBJECTS_DIR = obj
-MOC_DIR = moc
-
-RESOURCES += \
- quail.qrc
-
-OTHER_FILES += \
- 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 \
- android/version.xml \
- TODO.txt
+DEFINES += APP_DISPLAY_VERSION=\\\"0.1.0\\\"
+DEFINES += APP_MAJOR_VERSION=\\\"0\\\"
+
+TEMPLATE = app
+TARGET = Quail
+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\\\"
+
+#win32-g++ {
+# DEFINES += BUILDTIME=\\\"$$system('time/T')\\\"
+# DEFINES += BUILDDATE=\\\"$$system('echo %date%')\\\"
+#}
+#else {
+# DEFINES += BUILDTIME=\\\"$$system(date '+%H:%M.%s')\\\"
+# DEFINES += BUILDDATE=\\\"$$system(date '+%d/%m/%y')\\\"
+#}
+
+QT += core gui webkit
+greaterThan(QT_MAJOR_VERSION, 4) {
+ message("Using QT5")
+ DEFINES += USE_QT5
+ QT += widgets
+ QT += webkitwidgets
+ QT -= printsupport
+ QT -= sensors
+ QT -= qml
+ QT -= opengl
+ QT -= quick
+ QT -= network
+ QT -= multimedia
+ QT -= multimediawidgets
+}
+
+CONFIG = qt warn_on debug_and_release
+
+DISTFILES = \
+ AUTHORS \
+ ChangeLog \
+ NEWS \
+ README \
+ quail.png \
+ make.sh \
+ mkstuff.conf \
+ mkipk.sh \
+ mktarball.sh
+
+linux-g++* {
+ message("Using unix")
+ CONFIG += link_pkgconfig
+ PKGCONFIG += purple glib-2.0 gmodule-2.0
+}
+
+win32-g++ {
+ message("Using win32")
+ HEADERS += src/QuailWinGlibEventLoop.h
+ SOURCES += src/QuailWinGlibEventLoop.cpp
+
+ #RC_FILE = resource.rc
+
+ 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"
+}
+
+HEADERS = \
+ src/QuailAccountBox.h \
+ src/QuailAccountEditor.h \
+ src/QuailAccountsWindow.h \
+ src/QuailAction.h \
+ src/QuailBListWindow.h \
+ src/QuailBuddyList.h \
+ src/QuailConnectionMeter.h \
+ src/QuailConvButton.h \
+ src/QuailConvWindow.h \
+ src/QuailDebugWindow.h \
+ src/QuailEventLoop.h \
+ src/QuailDialogs.h \
+ src/QuailImageUtils.h \
+ src/QuailInputDialog.h \
+ src/QuailMainWindow.h \
+ src/QuailMultiLineEdit.h \
+ src/QuailNotify.h \
+ src/QuailPrefsDialog.h \
+ src/QuailProtocolBox.h \
+ src/QuailProtocolUtils.h \
+ src/QuailRequest.h \
+ src/QuailTabBar.h \
+ src/QuailTabWidget.h \
+ src/global.h \
+ src/QuailConvDisplay.h \
+ src/QuailStatusSelector.h \
+ src/QuailBlistItem.h
+
+
+SOURCES = \
+ 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/QuailDialogs.cpp \
+ src/QuailEventLoop.cpp \
+ src/QuailImageUtils.cpp \
+ src/QuailInputDialog.cpp \
+ src/QuailMainWindow.cpp \
+ src/QuailMultiLineEdit.cpp \
+ src/QuailNotify.cpp \
+ src/QuailPrefsDialog.cpp \
+ src/QuailProtocolBox.cpp \
+ src/QuailProtocolUtils.cpp \
+ src/QuailRequest.cpp \
+ src/QuailTabBar.cpp \
+ src/QuailTabWidget.cpp \
+ src/main.cpp \
+ src/QuailConvDisplay.cpp \
+ src/QuailStatusSelector.cpp \
+ src/QuailBlistItem.cpp
+
+
+
+RESOURCES += \
+ quail.qrc
+
+OTHER_FILES += \
+ 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 \
+ android/version.xml \
+ TODO.txt
--- 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";
}
void
--- 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 @@
typedef struct
{
- guint handle;
+ guint handle;
- union
- {
- QQuailTimer *timer;
- QQuailInputNotifier *notifier;
- };
+ union
+ {
+ QQuailTimer *timer;
+ QQuailInputNotifier *notifier;
+ };
} QQuailSourceInfo;
@@ -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()),
- this, SLOT(update()));
+ connect(this, SIGNAL(timeout()),
+ this, SLOT(update()));
}
void
QQuailTimer::update()
{
- if (!func(userData))
- qQuailSourceRemove(sourceId);
+ if (!func(userData))
+ qQuailSourceRemove(sourceId);
}
QQuailInputNotifier::QQuailInputNotifier(int fd,
@@ -59,50 +59,50 @@
PurpleInputFunction func,
gpointer userData)
: QObject(), func(func), userData(userData), readNotifier(NULL),
- writeNotifier(NULL)
+ writeNotifier(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)
- delete readNotifier;
+ if (readNotifier != NULL)
+ delete readNotifier;
- if (writeNotifier != NULL)
- delete writeNotifier;
+ if (writeNotifier != NULL)
+ delete writeNotifier;
}
void
QQuailInputNotifier::ioInvoke(int fd)
{
//qDebug() << "QQuailInputNotifier::ioInvoke";
- int cond = 0;
+ int cond = 0;
- 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);
- return info->handle;
+ return info->handle;
}
static gboolean
qQuailTimeoutRemove(guint handle)
{
//qDebug() << "QQuailInputNotifier::qQuailTimeoutRemove";
- qQuailSourceRemove(handle);
+ qQuailSourceRemove(handle);
- return 0;
+ return 0;
}
static guint
@@ -138,36 +138,36 @@
gpointer userData)
{
//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);
- return info->handle;
+ return info->handle;
}
static gboolean
qQuailSourceRemove(guint handle)
{
//qDebug() << "QQuailInputNotifier::qQuailSourceRemove";
- QQuailSourceInfo *info;
+ QQuailSourceInfo *info;
info = m_sources.value(handle);
- if (info == NULL)
+ if (info == NULL)
return false;
m_sources.remove(handle);
- if (info->timer != NULL)
- delete info->timer;
- else if (info->notifier != NULL)
- delete info->notifier;
+ if (info->timer != NULL)
+ delete info->timer;
+ else if (info->notifier != NULL)
+ delete info->notifier;
- delete info;
+ delete info;
return true;
}
@@ -203,5 +203,5 @@
PurpleEventLoopUiOps *
qQuailGetEventLoopUiOps(void)
{
- return &eventloop_ops;
+ return &eventloop_ops;
}
--- 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 <QTimer>
#include <QSocketNotifier>
/* http://harmattan-dev.nokia.com/docs/library/html/qt4/qabstracteventdispatcher.html */
-#include <QAbstractEventDispatcher>
+//#include <QAbstractEventDispatcher>
class QQuailTimer : public QTimer
{
- Q_OBJECT
+ Q_OBJECT
- public:
- QQuailTimer(guint sourceId, GSourceFunc func, gpointer data);
+ public:
+ QQuailTimer(guint sourceId, GSourceFunc func, gpointer data);
- private slots:
- void update();
+ private slots:
+ void update();
- private:
- guint sourceId;
- GSourceFunc func;
- gpointer userData;
+ private:
+ guint sourceId;
+ GSourceFunc func;
+ gpointer userData;
};
class QQuailInputNotifier : public QObject
{
- Q_OBJECT
+ Q_OBJECT
- public:
- QQuailInputNotifier(int fd, PurpleInputCondition cond,
- PurpleInputFunction func, gpointer userData);
- ~QQuailInputNotifier();
+ public:
+ QQuailInputNotifier(int fd, PurpleInputCondition cond,
+ PurpleInputFunction func, gpointer userData);
+ ~QQuailInputNotifier();
- private slots:
- void ioInvoke(int fd);
+ private slots:
+ void ioInvoke(int fd);
- private:
- PurpleInputCondition cond;
- PurpleInputFunction func;
- gpointer userData;
- QSocketNotifier *readNotifier, *writeNotifier;
+ private:
+ PurpleInputCondition cond;
+ PurpleInputFunction func;
+ gpointer userData;
+ 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>
+#include <glib.h>
+
+struct GPollFDWithQSocketNotifier
+{
+ GPollFD pollfd;
+ QSocketNotifier *socketNotifier;
+};
+
+struct GSocketNotifierSource
+{
+ GSource source;
+ QList<GPollFDWithQSocketNotifier *> pollfds;
+};
+
+static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout)
+{
+ if (timeout)
+ *timeout = -1;
+ return false;
+}
+
+static gboolean socketNotifierSourceCheck(GSource *source)
+{
+ GSocketNotifierSource *src = reinterpret_cast<GSocketNotifierSource *>(source);
+
+ bool pending = false;
+ 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);
+ }
+
+ return pending;
+}
+
+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,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct GTimerSource
+{
+ GSource source;
+ 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);
+ else
+ *timeout = -1;
+
+ return (*timeout == 0);
+}
+
+static gboolean timerSourceCheckHelper(GTimerSource *src)
+{
+ if (src->timerList.isEmpty()
+ || (src->processEventsFlags & QEventLoop::X11ExcludeTimers))
+ return false;
+
+ if (src->timerList.updateCurrentTime() < src->timerList.first()->timeout)
+ return false;
+
+ return true;
+}
+
+static gboolean timerSourcePrepare(GSource *source, gint *timeout)
+{
+ gint dummy;
+ if (!timeout)
+ timeout = &dummy;
+
+ GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
+ if (src->runWithIdlePriority) {
+ if (timeout)
+ *timeout = -1;
+ return false;
+ }
+
+ return timerSourcePrepareHelper(src, timeout);
+}
+
+static gboolean timerSourceCheck(GSource *source)
+{
+ GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
+ if (src->runWithIdlePriority)
+ return false;
+ return timerSourceCheckHelper(src);
+}
+
+static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer)
+{
+ GTimerSource *timerSource = reinterpret_cast<GTimerSource *>(source);
+ if (timerSource->processEventsFlags & QEventLoop::X11ExcludeTimers)
+ return true;
+ timerSource->runWithIdlePriority = true;
+ (void) timerSource->timerList.activateTimers();
+ return true; // ??? don't remove, right again?
+}
+
+static GSourceFuncs timerSourceFuncs = {
+ timerSourcePrepare,
+ timerSourceCheck,
+ timerSourceDispatch,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct GIdleTimerSource
+{
+ GSource source;
+ 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
+ if (timeout)
+ *timeout = -1;
+ return false;
+ }
+
+ 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 false;
+ }
+ return timerSourceCheckHelper(timerSource);
+}
+
+static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer)
+{
+ GTimerSource *timerSource = reinterpret_cast<GIdleTimerSource *>(source)->timerSource;
+ (void) timerSourceDispatch(&timerSource->source, 0, 0);
+ return true;
+}
+
+static GSourceFuncs idleTimerSourceFuncs = {
+ idleTimerSourcePrepare,
+ idleTimerSourceCheck,
+ idleTimerSourceDispatch,
+ NULL,
+ NULL,
+ NULL
+};
+
+struct GPostEventSource
+{
+ GSource source;
+ QAtomicInt serialNumber;
+ int lastSerialNumber;
+ QuailEventDispatcherWinGlib *d;
+};
+
+static gboolean postEventSourcePrepare(GSource *s, gint *timeout)
+{
+ QThreadData *data = QThreadData::current();
+ if (!data)
+ return false;
+
+ gint dummy;
+ if (!timeout)
+ timeout = &dummy;
+ const bool canWait = data->canWaitLocked();
+ *timeout = canWait ? -1 : 0;
+
+ GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
+ return (!canWait
+ || (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,
+ postEventSourceCheck,
+ postEventSourceDispatch,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+HINSTANCE qWinAppInst();
+extern uint qGlobalPostedEventsCount();
+
+#ifndef TIME_KILL_SYNCHRONOUS
+# define TIME_KILL_SYNCHRONOUS 0x0100
+#endif
+
+#ifndef QS_RAWINPUT
+# ifdef Q_OS_WINCE
+# define QS_RAWINPUT 0x0000
+# else
+# define QS_RAWINPUT 0x0400
+# endif
+#endif
+
+#ifndef WM_TOUCH
+# define WM_TOUCH 0x0240
+#endif
+#ifndef QT_NO_GESTURES
+#ifndef WM_GESTURE
+# define WM_GESTURE 0x0119
+#endif
+#ifndef WM_GESTURENOTIFY
+# define WM_GESTURENOTIFY 0x011A
+#endif
+#endif // QT_NO_GESTURES
+
+enum {
+ WM_QT_SOCKETNOTIFIER = WM_USER,
+ WM_QT_SENDPOSTEDEVENTS = WM_USER + 1,
+ SendPostedEventsWindowsTimerId = ~1u
+};
+
+#if defined(Q_OS_WINCE)
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <winsock.h>
+QT_END_INCLUDE_NAMESPACE
+// Asynchronous Winsocks ------------------------------------------
+#ifndef QT_NO_THREAD
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <qthread.h>
+#include <qmap.h>
+#include <qmutex.h>
+QT_END_INCLUDE_NAMESPACE
+
+//#define QCE_ASYNC_DEBUG
+
+namespace {
+ class SocketAsyncHandler;
+
+ class SocketAsyncHandler : public QThread
+ {
+ public:
+ SocketAsyncHandler();
+ ~SocketAsyncHandler();
+ void run();
+ void select(SOCKET sock, HWND handle, unsigned int msg, long ev);
+ void removeSelect(SOCKET sock);
+ void safeRemove(SOCKET sock);
+ private:
+ struct SockInfo {
+ HWND handle;
+ unsigned int msg;
+ long ev;
+ };
+ QMap<SOCKET, SockInfo> sockets;
+ QMutex mutex;
+ QWaitCondition cond;
+ bool supposedToDie;
+ };
+
+ SocketAsyncHandler::SocketAsyncHandler()
+ : supposedToDie(false)
+ {
+ }
+
+ SocketAsyncHandler::~SocketAsyncHandler()
+ {
+ mutex.lock();
+ supposedToDie = true;
+ mutex.unlock();
+ cond.wakeOne();
+ wait();
+ while (sockets.size() > 0)
+ removeSelect(sockets.begin().key());
+ }
+
+ void SocketAsyncHandler::removeSelect(SOCKET sock)
+ {
+ if (!sockets.contains(sock))
+ return;
+ sockets.remove(sock);
+ return;
+ }
+
+ void SocketAsyncHandler::safeRemove(SOCKET sock)
+ {
+ QMutexLocker locker(&mutex);
+ removeSelect(sock);
+ }
+
+ void SocketAsyncHandler::select(SOCKET sock, HWND handle, unsigned int msg, long ev)
+ {
+ QMutexLocker locker(&mutex);
+
+ if (sockets.contains(sock))
+ sockets.remove(sock);
+
+ SockInfo info;
+ info.handle = handle;
+ info.msg = msg;
+ info.ev = ev;
+ sockets.insert(sock, info);
+ cond.wakeOne();
+ }
+
+ void SocketAsyncHandler::run()
+ {
+ do {
+ mutex.lock();
+
+ while (!supposedToDie && sockets.isEmpty()) {
+ cond.wait(&mutex);
+ }
+
+ if (supposedToDie) {
+ mutex.unlock();
+ break;
+ }
+
+ // Copy current items to reduce lock time
+ // and to be able to use SendMessage
+ QMap<SOCKET, SockInfo> currentSockets = sockets;
+ mutex.unlock();
+
+ fd_set readS, writeS, exS;
+ FD_ZERO(&readS);
+ FD_ZERO(&writeS);
+ FD_ZERO(&exS);
+
+ int maxFd = 0;
+
+ for (QMap<SOCKET, SockInfo>::iterator it = currentSockets.begin(); it != currentSockets.end(); ++it) {
+ const SockInfo &info = it.value();
+ int socket = it.key();
+ 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);
+ if (info.ev & FD_OOB)
+ FD_SET(socket, &exS);
+ }
+
+ timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 50000;
+ int result = ::select(maxFd + 1, &readS, &writeS, &exS, &timeout);
+ if (result > 0) {
+ HWND handle;
+ unsigned int tmpMsg;
+ SOCKET sock;
+ HRESULT ret;
+ for (QMap<SOCKET, SockInfo>::const_iterator it = currentSockets.constBegin();
+ it != currentSockets.constEnd(); ++it) {
+ handle = (*it).handle;
+ tmpMsg = (*it).msg;
+ sock = it.key();
+ 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);
+ }
+ }
+
+#ifdef QCE_ASYNC_DEBUG
+ 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
+ // ### broken one.
+ qWarning("WSAAsync select error %d", WSAGetLastError());
+ }
+#endif
+ } while(true);
+ }
+} // namespace
+
+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);
+ return SOCKET_ERROR;
+ }
+
+ if (msg == 0 && ev == 0)
+ qt_async_handler()->safeRemove(sock);
+ else
+ qt_async_handler()->select(sock, handle, msg, ev);
+
+ qt_async_handler()->start(QThread::LowPriority);
+ WSASetLastError(0);
+ return 0;
+}
+#else // QT_NO_THREAD
+int WSAAsyncSelect(SOCKET, HWND, unsigned int, long)
+{
+ return SOCKET_ERROR;
+}
+#endif
+#endif // Q_OS_WINCE
+
+#if !defined(DWORD_PTR) && !defined(Q_OS_WIN64)
+#define DWORD_PTR DWORD
+#endif
+
+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;
+ if (!triedResolve) {
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
+ if (triedResolve)
+ return;
+#endif
+ triedResolve = true;
+#if !defined(Q_OS_WINCE)
+# if defined(_MSC_VER) && _MSC_VER >= 1700
+ if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8) {
+# else
+ {
+# endif
+ qtimeSetEvent = (ptimeSetEvent)QSystemLibrary::resolve(QLatin1String("winmm"), "timeSetEvent");
+ qtimeKillEvent = (ptimeKillEvent)QSystemLibrary::resolve(QLatin1String("winmm"), "timeKillEvent");
+ }
+#else
+ qtimeSetEvent = (ptimeSetEvent)QSystemLibrary::resolve(QLatin1String("Mmtimer"), "timeSetEvent");
+ qtimeKillEvent = (ptimeKillEvent)QSystemLibrary::resolve(QLatin1String("Mmtimer"), "timeKillEvent");
+#endif
+ }
+}
+
+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)
+{
+ resolveTimerAPI();
+#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_thread_init(NULL);
+ }
+#endif
+
+ if (mainContext) {
+ g_main_context_ref(mainContext);
+ } else {
+ QCoreApplication *app = QCoreApplication::instance();
+ if (app && QThread::currentThread() == app->thread()) {
+ mainContext = g_main_context_default();
+ g_main_context_ref(mainContext);
+ } else {
+ mainContext = g_main_context_new();
+ }
+ }
+
+#if GLIB_CHECK_VERSION (2, 22, 0)
+ g_main_context_push_thread_default (mainContext);
+#endif
+
+ // 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
+ 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()
+{
+ if (internalHwnd)
+ 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
+ return;
+ WinTimerInfo *t = (WinTimerInfo*)user;
+ Q_ASSERT(t);
+ 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)
+ return true;
+
+ MSG msg;
+ msg.hwnd = hwnd;
+ msg.message = message;
+ msg.wParam = wp;
+ msg.lParam = lp;
+ QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
+ long result;
+ if (!dispatcher) {
+ if (message == WM_TIMER)
+ KillTimer(hwnd, wp);
+ return 0;
+ } else if (dispatcher->filterNativeEvent(QByteArrayLiteral("windows_dispatcher_MSG"), &msg, &result)) {
+ return result;
+ }
+
+#ifdef GWLP_USERDATA
+ QuailEventDispatcherWinGlib *q = (QuailEventDispatcherWinGlib *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
+#else
+ QuailEventDispatcherWinGlib *q = (QuailEventDispatcherWinGlib *) GetWindowLong(hwnd, GWL_USERDATA);
+#endif
+ QuailEventDispatcherWinGlib *d = 0;
+ if (q != 0)
+ d = q->d_func();
+
+ if (message == WM_QT_SOCKETNOTIFIER) {
+ // socket notifier message
+ int type = -1;
+ switch (WSAGETSELECTEVENT(lp)) {
+ case FD_READ:
+ case FD_ACCEPT:
+ type = 0;
+ break;
+ case FD_WRITE:
+ case FD_CONNECT:
+ type = 1;
+ break;
+ case FD_OOB:
+ type = 2;
+ break;
+ case FD_CLOSE:
+ type = 3;
+ break;
+ }
+ if (type >= 0) {
+ Q_ASSERT(d != 0);
+ 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;
+ if (sn) {
+ if (type < 3) {
+ QEvent event(QEvent::SockAct);
+ QCoreApplication::sendEvent(sn->obj, &event);
+ } else {
+ QEvent event(QEvent::SockClose);
+ QCoreApplication::sendEvent(sn->obj, &event);
+ }
+ }
+ }
+ return 0;
+ } 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;
+ q->sendPostedEvents();
+ }
+ return 0;
+ } else if (message == WM_TIMER) {
+ Q_ASSERT(d != 0);
+ d->sendTimerEvent(wp);
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, message, wp, lp);
+}
+
+LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
+{
+ if (wp == PM_REMOVE) {
+ QuailEventDispatcherWinGlib *q = qobject_cast<QuailEventDispatcherWinGlib *>(QAbstractEventDispatcher::instance());
+ Q_ASSERT(q != 0);
+ if (q) {
+ MSG *msg = (MSG *) lp;
+ 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
+ NULL);
+ // 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
+ }
+ }
+ }
+#ifdef Q_OS_WINCE
+ return 0;
+#else
+ return CallNextHookEx(0, code, wp, lp);
+#endif
+}
+
+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));
+
+ WNDCLASS wc;
+ wc.style = 0;
+ wc.lpfnWndProc = qt_internal_proc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = qWinAppInst();
+ wc.hIcon = 0;
+ wc.hCursor = 0;
+ wc.hbrBackground = 0;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = reinterpret_cast<const wchar_t *> (className.utf16());
+
+ RegisterClass(&wc);
+#ifdef Q_OS_WINCE
+ HWND parent = 0;
+#else
+ HWND parent = HWND_MESSAGE;
+#endif
+ HWND wnd = CreateWindow(wc.lpszClassName, // classname
+ wc.lpszClassName, // window name
+ 0, // style
+ 0, 0, 0, 0, // geometry
+ parent, // parent
+ 0, // menu handle
+ qWinAppInst(), // application
+ 0); // windows creation data.
+
+ if (!wnd) {
+ qWarning("QEventDispatcher: Failed to create QuailEventDispatcherWinGlib internal window: %d\n", (int)GetLastError());
+ }
+
+#ifdef GWLP_USERDATA
+ SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher);
+#else
+ SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher);
+#endif
+
+ return wnd;
+}
+
+void QuailEventDispatcherWinGlib::registerTimer(WinTimerInfo *t)
+{
+ Q_ASSERT(internalHwnd);
+
+ Q_Q(QuailEventDispatcherWinGlib);
+
+ int ok = 0;
+ uint interval = t->interval;
+ if (interval == 0u) {
+ // optimization for single-shot-zero-timer
+ QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
+ ok = 1;
+ } 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;
+ }
+ if (ok == 0) {
+ // 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;
+
+ if (ok == 0)
+ 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);
+ }
+ delete t;
+}
+
+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);
+ if (t) {
+ t->inTimerEvent = false;
+ }
+ }
+}
+
+void QuailEventDispatcherWinGlib::doWsaAsyncSelect(int socket)
+{
+ Q_ASSERT(internalHwnd);
+ int sn_event = 0;
+ 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))
+ sn_event |= FD_OOB;
+ // 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);
+ if (d->internalHwnd)
+ return;
+ d->internalHwnd = qt_create_internal_window(this);
+
+#ifndef Q_OS_WINCE
+ // 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");
+ }
+#endif
+
+ // 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()
+ wakeUp();
+}
+
+bool QuailEventDispatcherWinGlib::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ Q_D(QuailEventDispatcherWinGlib);
+
+ if (!d->internalHwnd)
+ createInternalHwnd();
+
+ d->interruptFlag = false;
+ emit awake();
+
+ bool canWait;
+ bool retVal = false;
+ bool seenWM_QT_SENDPOSTEDEVENTS = false;
+ bool needWM_QT_SENDPOSTEDEVENTS = false;
+ do {
+ DWORD waitRet = 0;
+ HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
+ QVarLengthArray<MSG> processedTimers;
+ while (!d->interruptFlag) {
+ DWORD nCount = d->winEventNotifierList.count();
+ Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
+
+ MSG msg;
+ bool haveMessage;
+
+ if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
+ // process queued user input events
+ haveMessage = true;
+ msg = d->queuedUserInputEvents.takeFirst();
+ } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
+ // process queued socket events
+ haveMessage = true;
+ msg = d->queuedSocketEvents.takeFirst();
+ } else {
+ 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
+#ifndef QT_NO_GESTURES
+ || msg.message == WM_GESTURE
+ || msg.message == WM_GESTURENOTIFY
+#endif
+ || msg.message == WM_CLOSE)) {
+ // queue user input events for later processing
+ haveMessage = false;
+ d->queuedUserInputEvents.append(msg);
+ }
+ if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)
+ && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
+ // queue socket events for later processing
+ haveMessage = false;
+ d->queuedSocketEvents.append(msg);
+ }
+ }
+ if (!haveMessage) {
+ // 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
+ continue;
+ }
+ }
+ if (haveMessage) {
+#ifdef Q_OS_WINCE
+ // WinCE doesn't support hooks at all, so we have to call this by hand :(
+ (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg);
+#endif
+
+ if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
+ if (seenWM_QT_SENDPOSTEDEVENTS) {
+ // when calling processEvents() "manually", we only want to send posted
+ // events once
+ needWM_QT_SENDPOSTEDEVENTS = true;
+ continue;
+ }
+ seenWM_QT_SENDPOSTEDEVENTS = true;
+ } else if (msg.message == WM_TIMER) {
+ // avoid live-lock by keeping track of the timers we've already sent
+ bool found = false;
+ 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);
+ }
+ if (found)
+ continue;
+ processedTimers.append(msg);
+ } else if (msg.message == WM_QUIT) {
+ if (QCoreApplication::instance())
+ QCoreApplication::instance()->quit();
+ return false;
+ }
+
+ if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } else if (waitRet - WAIT_OBJECT_0 < nCount) {
+ d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
+ } else {
+ // nothing todo so break
+ break;
+ }
+ retVal = true;
+ }
+
+ // still nothing - wait for message or signalled objects
+ canWait = (!retVal
+ && !d->interruptFlag
+ && (flags & QEventLoop::WaitForMoreEvents));
+ if (canWait) {
+ 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();
+
+ emit aboutToBlock();
+ waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
+ emit awake();
+ if (waitRet - WAIT_OBJECT_0 < nCount) {
+ d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
+ retVal = true;
+ }
+ }
+ } while (canWait);
+
+ if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) {
+ // when called "manually", always send posted events
+ sendPostedEvents();
+ }
+
+ if (needWM_QT_SENDPOSTEDEVENTS)
+ PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
+
+ return retVal;
+}
+
+bool QuailEventDispatcherWinGlib::hasPendingEvents()
+{
+ MSG msg;
+ return qGlobalPostedEventsCount() || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
+}
+
+void QuailEventDispatcherWinGlib::registerSocketNotifier(QSocketNotifier *notifier)
+{
+ Q_ASSERT(notifier);
+ int sockfd = notifier->socket();
+ int type = notifier->type();
+#ifndef QT_NO_DEBUG
+ if (sockfd < 0) {
+ qWarning("QSocketNotifier: Internal error");
+ return;
+ } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
+ return;
+ }
+#endif
+
+ 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;
+ sn->obj = notifier;
+ sn->fd = sockfd;
+ dict->insert(sn->fd, sn);
+
+ if (d->internalHwnd)
+ d->doWsaAsyncSelect(sockfd);
+}
+
+void QuailEventDispatcherWinGlib::unregisterSocketNotifier(QSocketNotifier *notifier)
+{
+ Q_ASSERT(notifier);
+ int sockfd = notifier->socket();
+ int type = notifier->type();
+#ifndef QT_NO_DEBUG
+ if (sockfd < 0) {
+ qWarning("QSocketNotifier: Internal error");
+ return;
+ } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
+ return;
+ }
+#endif
+
+ 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);
+ if (!sn)
+ return;
+
+ dict->remove(sockfd);
+ delete sn;
+
+ if (d->internalHwnd)
+ 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");
+ return;
+ } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QObject::startTimer: timers cannot be started from another thread");
+ return;
+ }
+
+ Q_D(QuailEventDispatcherWinGlib);
+
+ WinTimerInfo *t = new WinTimerInfo;
+ t->dispatcher = this;
+ t->timerId = timerId;
+ t->interval = interval;
+ t->timerType = timerType;
+ t->obj = object;
+ t->inTimerEvent = false;
+ t->fastTimerId = 0;
+
+ if (d->internalHwnd)
+ d->registerTimer(t);
+
+ d->timerVec.append(t); // store in timer vector
+ d->timerDict.insert(t->timerId, t); // store timers in dict
+}
+
+bool QuailEventDispatcherWinGlib::unregisterTimer(int timerId)
+{
+ if (timerId < 1) {
+ qWarning("QuailEventDispatcherWinGlib::unregisterTimer: invalid argument");
+ return false;
+ }
+ QThread *currentThread = QThread::currentThread();
+ if (thread() != currentThread) {
+ qWarning("QObject::killTimer: timers cannot be stopped from another thread");
+ return false;
+ }
+
+ Q_D(QuailEventDispatcherWinGlib);
+ if (d->timerVec.isEmpty() || timerId <= 0)
+ return false;
+
+ WinTimerInfo *t = d->timerDict.value(timerId);
+ if (!t)
+ return false;
+
+ d->timerDict.remove(t->timerId);
+ d->timerVec.removeAll(t);
+ d->unregisterTimer(t);
+ return true;
+}
+
+bool QuailEventDispatcherWinGlib::unregisterTimers(QObject *object)
+{
+ if (!object) {
+ qWarning("QuailEventDispatcherWinGlib::unregisterTimers: invalid argument");
+ return false;
+ }
+ QThread *currentThread = QThread::currentThread();
+ if (object->thread() != thread() || thread() != currentThread) {
+ qWarning("QObject::killTimers: timers cannot be stopped from another thread");
+ return false;
+ }
+
+ Q_D(QuailEventDispatcherWinGlib);
+ if (d->timerVec.isEmpty())
+ return false;
+ register WinTimerInfo *t;
+ for (int i=0; i<d->timerVec.size(); i++) {
+ t = d->timerVec.at(i);
+ if (t && t->obj == object) { // object found
+ d->timerDict.remove(t->timerId);
+ d->timerVec.removeAt(i);
+ d->unregisterTimer(t);
+ --i;
+ }
+ }
+ return true;
+}
+
+QList<QuailEventDispatcherWinGlib::TimerInfo>
+QuailEventDispatcherWinGlib::registeredTimers(QObject *object) const
+{
+ if (!object) {
+ qWarning("QuailEventDispatcherWinGlib:registeredTimers: invalid argument");
+ return QList<TimerInfo>();
+ }
+
+ Q_D(const QuailEventDispatcherWinGlib);
+ QList<TimerInfo> list;
+ 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);
+ }
+ return list;
+}
+
+bool QuailEventDispatcherWinGlib::registerEventNotifier(QWinEventNotifier *notifier)
+{
+ if (!notifier) {
+ qWarning("QWinEventNotifier: Internal error");
+ return false;
+ } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QWinEventNotifier: event notifiers cannot be enabled from another thread");
+ return false;
+ }
+
+ Q_D(QuailEventDispatcherWinGlib);
+
+ if (d->winEventNotifierList.contains(notifier))
+ return true;
+
+ if (d->winEventNotifierList.count() >= MAXIMUM_WAIT_OBJECTS - 2) {
+ qWarning("QWinEventNotifier: Cannot have more than %d enabled at one time", MAXIMUM_WAIT_OBJECTS - 2);
+ return false;
+ }
+ d->winEventNotifierList.append(notifier);
+ return true;
+}
+
+void QuailEventDispatcherWinGlib::unregisterEventNotifier(QWinEventNotifier *notifier)
+{
+ if (!notifier) {
+ qWarning("QWinEventNotifier: Internal error");
+ return;
+ } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QWinEventNotifier: event notifiers cannot be disabled from another thread");
+ return;
+ }
+
+ Q_D(QuailEventDispatcherWinGlib);
+
+ int i = d->winEventNotifierList.indexOf(notifier);
+ if (i != -1)
+ 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));
+#else
+ if (WaitForSingleObject(d->winEventNotifierList.at(i)->handle(), 0) == WAIT_OBJECT_0)
+ d->activateEventNotifier(d->winEventNotifierList.at(i));
+#endif
+ }
+}
+
+int QuailEventDispatcherWinGlib::remainingTime(int timerId)
+{
+#ifndef QT_NO_DEBUG
+ if (timerId < 1) {
+ qWarning("QuailEventDispatcherWinGlib::remainingTime: invalid argument");
+ return -1;
+ }
+#endif
+
+ Q_D(QuailEventDispatcherWinGlib);
+
+ if (d->timerVec.isEmpty())
+ return -1;
+
+ quint64 currentTime = qt_msectime();
+
+ register WinTimerInfo *t;
+ for (int i=0; i<d->timerVec.size(); i++) {
+ t = d->timerVec.at(i);
+ if (t && t->timerId == timerId) { // timer found
+ if (currentTime < t->timeout) {
+ // time to wait
+ return t->timeout - currentTime;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+#ifndef QT_NO_DEBUG
+ qWarning("QuailEventDispatcherWinGlib::remainingTime: timer id %d not found", timerId);
+#endif
+
+ return -1;
+}
+
+void QuailEventDispatcherWinGlib::wakeUp()
+{
+ Q_D(QuailEventDispatcherWinGlib);
+ d->serialNumber.ref();
+ 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;
+ wakeUp();
+}
+
+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);
+
+ // clean up any timers
+ for (int i = 0; i < d->timerVec.count(); ++i)
+ d->unregisterTimer(d->timerVec.at(i));
+ d->timerVec.clear();
+ d->timerDict.clear();
+
+#ifndef Q_OS_WINCE
+ if (d->getMessageHook)
+ UnhookWindowsHookEx(d->getMessageHook);
+ d->getMessageHook = 0;
+#endif
+}
+
+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());
+ if (t) {
+ t->inTimerEvent = true;
+
+ QTimerEvent te(zte->timerId());
+ QCoreApplication::sendEvent(t->obj, &te);
+
+ t = d->timerDict.value(zte->timerId());
+ if (t) {
+ 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;
+ }
+ }
+ return true;
+ } 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>
+#include <QHash>
+
+typedef struct _GMainContext GMainContext;
+
+class QWinEventNotifier;
+class QuailEventDispatcherWinGlibPrivate;
+
+// forward declaration
+LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
+int qt_msectime();
+
+struct GPostEventSource;
+struct GSocketNotifierSource;
+struct GTimerSource;
+struct GIdleTimerSource;
+
+struct QSockNot {
+ QSocketNotifier *obj;
+ int fd;
+};
+
+typedef QHash<int, QSockNot *> QSNDict;
+
+struct WinTimerInfo { // internal timer info
+ QObject *dispatcher;
+ int timerId;
+ int interval;
+ Qt::TimerType timerType;
+ quint64 timeout; // - when to actually fire
+ QObject *obj; // - object to receive events
+ bool inTimerEvent;
+ int fastTimerId;
+};
+
+class QZeroTimerEvent : public QTimerEvent
+{
+public:
+ explicit inline QZeroTimerEvent(int timerId)
+ : QTimerEvent(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
+{
+ Q_OBJECT
+ void createInternalHwnd();
+
+public:
+ 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);
+
+ void wakeUp();
+ void interrupt();
+ void flush();
+
+ void startingUp();
+ void closingDown();
+
+ bool event(QEvent *e);
+
+ /* Glib */
+ static bool versionSupported();
+
+ GMainContext *mainContext;
+ GPostEventSource *postEventSource;
+ GSocketNotifierSource *socketNotifierSource;
+ GTimerSource *timerSource;
+ GIdleTimerSource *idleTimerSource;
+
+ void runTimersOnceWithNormalPriority();
+
+ DWORD threadId;
+
+ bool interruptFlag;
+
+ // internal window handle used for socketnotifiers/timers/etc
+ HWND internalHwnd;
+ HHOOK getMessageHook;
+
+ // for controlling when to send posted events
+ QAtomicInt serialNumber;
+ int lastSerialNumber, sendPostedEventsWindowsTimerId;
+ QAtomicInt wakeUps;
+
+ // timers
+ WinTimerVec timerVec;
+ WinTimerDict timerDict;
+ void registerTimer(WinTimerInfo *t);
+ void unregisterTimer(WinTimerInfo *t);
+ void sendTimerEvent(int timerId);
+
+ // socket notifiers
+ QSNDict sn_read;
+ QSNDict sn_write;
+ QSNDict sn_except;
+ void doWsaAsyncSelect(int socket);
+
+ QList<QWinEventNotifier *> winEventNotifierList;
+ void activateEventNotifier(QWinEventNotifier * wen);
+
+ QList<MSG> queuedUserInputEvents;
+ QList<MSG> queuedSocketEvents;
+
+protected:
+ virtual void sendPostedEvents();
+
+private:
+ 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,
* MA 02111-1307 USA
*/
+
+#ifdef Q_OS_CYGWIN
+#include "QuailWinGlibEventLoop.h"
+#endif
+
#include "QuailMainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
+#ifdef Q_OS_CYGWIN
+ QuailEventDispatcherWinGlib quailEventLoop;
+#endif
QApplication a(argc, argv);
QQuailMainWindow w;
w.show();