--- a/src/QuailEventLoop.cpp Fri Sep 13 14:11:27 2013 +0100
+++ b/src/QuailEventLoop.cpp Mon Sep 16 16:27:25 2013 +0100
@@ -21,157 +21,114 @@
#include "QuailEventLoop.h"
+ QQuailInputNotifier *notifier; static gboolean qQuailSourceRemove(guint handle);
-static gboolean qQuailTimeoutRemove(guint handle);
-static QuailEventLoop *eventLoop = NULL;
+static guint nextSourceId = 0; +static QMap<guint, QQuailSourceInfo*> m_sources; -QQuailTimer::QQuailTimer(GSourceFunc func, gpointer data)
- : QTimer(eventLoop), func(func), userData(data)
+QQuailTimer::QQuailTimer(guint sourceId, GSourceFunc func, gpointer data) + : QTimer(), sourceId(sourceId), func(func), userData(data) - connect(this, SIGNAL(timeout()),
+ connect(this, SIGNAL(timeout()),
- qQuailTimeoutRemove(sourceId);
-QQuailTimer::setHandle(guint newSourceId)
+ qQuailSourceRemove(sourceId); QQuailInputNotifier::QQuailInputNotifier(int fd,
PurpleInputCondition cond,
PurpleInputFunction func,
- : QObject(eventLoop), func(func), userData(userData), readNotifier(NULL),
+ : 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);
-QuailEventLoop::QuailEventLoop(QObject *parent) :
-bool QuailEventLoop::processEvents(QEventLoop::ProcessEventsFlags flags)
-bool QuailEventLoop::hasPendingEvents()
- return (m_timers.count() + m_sources.count()) > 0;
+ func(userData, fd, (PurpleInputCondition)cond); -void QuailEventLoop::registerSocketNotifier(QSocketNotifier *notifier)
-void QuailEventLoop::unregisterSocketNotifier(QSocketNotifier *notifier)
-void QuailEventLoop::registerTimer(int timerId, int interval, QObject *object)
-bool QuailEventLoop::unregisterTimer(int timerId)
- qQuailTimeoutRemove(timerId);
-bool QuailEventLoop::unregisterTimers(QObject *object)
- qQuailTimeoutRemove(m_timers.indexOf(object));
-QList<QAbstractEventDispatcher::TimerInfo>
-QuailEventLoop::registeredTimers(QObject *object) const
- /* Not implemented, we won't use this. It's only used for
- transfering QObject from one thread to another. */
- return QList<QAbstractEventDispatcher::TimerInfo>();
qQuailTimeoutAdd(guint interval, GSourceFunc func, gpointer data)
//qDebug() << "QQuailInputNotifier::qQuailTimeoutAdd";
- QQuailTimer *timer = new QQuailTimer(func, data);
- eventLoop->m_timers.append(timer);
- guint handle = eventLoop->m_timers.lastIndexOf(timer);
- timer->setHandle(handle);
- timer->start(interval);
+ QQuailSourceInfo *info = new QQuailSourceInfo; + info->handle = nextSourceId++;
+ info->timer = new QQuailTimer(info->handle, func, data); + info->timer->start(interval); + m_sources.insert(info->handle, info); qQuailTimeoutRemove(guint handle)
//qDebug() << "QQuailInputNotifier::qQuailTimeoutRemove";
- QQuailTimer *timer = eventLoop->m_timers.takeAt(handle);
+ qQuailSourceRemove(handle);
@@ -181,21 +138,36 @@
//qDebug() << "QQuailInputNotifier::qQuailInputAdd";
- QQuailInputNotifier *notifier = new QQuailInputNotifier(fd, cond, func, userData);
- eventLoop->m_sources.append(notifier);
- return eventLoop->m_sources.lastIndexOf(notifier);
+ QQuailSourceInfo *info = new QQuailSourceInfo; + info->handle = nextSourceId++; + info->notifier = new QQuailInputNotifier(fd, cond, func, userData); + m_sources.insert(info->handle, info); qQuailSourceRemove(guint handle)
//qDebug() << "QQuailInputNotifier::qQuailSourceRemove";
- QQuailInputNotifier *notifier = eventLoop->m_sources.takeAt(handle);
+ QQuailSourceInfo *info;
+ info = m_sources.value(handle);
+ m_sources.remove(handle); + if (info->timer != NULL) + else if (info->notifier != NULL) @@ -231,5 +203,5 @@
qQuailGetEventLoopUiOps(void)
--- a/src/QuailEventLoop.h Fri Sep 13 14:11:27 2013 +0100
+++ b/src/QuailEventLoop.h Mon Sep 16 16:27:25 2013 +0100
@@ -24,81 +24,44 @@
#include <libpurple/eventloop.h>
#include <QSocketNotifier>
/* http://harmattan-dev.nokia.com/docs/library/html/qt4/qabstracteventdispatcher.html */
-#include <QAbstractEventDispatcher>
- QQuailTimer *quailTimer;
+//#include <QAbstractEventDispatcher> class QQuailTimer : public QTimer
- QQuailTimer(GSourceFunc func, gpointer data);
+ QQuailTimer(guint sourceId, GSourceFunc func, gpointer data);
- void setHandle(guint newSourceId);
class QQuailInputNotifier : public QObject
- QQuailInputNotifier(int fd, PurpleInputCondition cond,
- PurpleInputFunction func, gpointer userData);
- ~QQuailInputNotifier();
- PurpleInputCondition cond;
- PurpleInputFunction func;
- QSocketNotifier *readNotifier, *writeNotifier;
-class QuailEventLoop : QAbstractEventDispatcher
- QuailEventLoop(QObject *parent = 0);
- bool processEvents(QEventLoop::ProcessEventsFlags flags);
- bool hasPendingEvents();
- void registerSocketNotifier(QSocketNotifier *notifier);
- void unregisterSocketNotifier(QSocketNotifier *notifier);
+ QQuailInputNotifier(int fd, PurpleInputCondition cond, + PurpleInputFunction func, gpointer userData); + ~QQuailInputNotifier(); - void registerTimer(int timerId, int interval, QObject *object);
- bool unregisterTimer(int timerId);
- bool unregisterTimers(QObject *object);
- QList<TimerInfo> registeredTimers(QObject *object) const;
- QList<QQuailInputNotifier*> m_sources;
- QList<QQuailTimer*> m_timers;
- //static QMap<guint, QQuailSourceInfo*> m_sources;
+ PurpleInputCondition cond; + PurpleInputFunction func; + QSocketNotifier *readNotifier, *writeNotifier; --- a/src/QuailWinGlibEventLoop.cpp Fri Sep 13 14:11:27 2013 +0100
+++ b/src/QuailWinGlibEventLoop.cpp Mon Sep 16 16:27:25 2013 +0100
@@ -1,6 +1,243 @@
#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; + QuailEventDispatcherWinGlibPrivate *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, extern uint qGlobalPostedEventsCount();
@@ -265,11 +502,73 @@
-QuailEventDispatcherWinGliPrivateb::QuailEventDispatcherWinGlibPrivate()
- : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0), getMessageHook(0),
+QuailEventDispatcherWinGlibPrivate::QuailEventDispatcherWinGlibPrivate(GMainContext *context = 0) + : mainContext(context), threadId(GetCurrentThreadId()), interrupt(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 QuailEventDispatcherWinGlibPrivate::runTimersOnceWithNormalPriority() + timerSource->runWithIdlePriority = false; QuailEventDispatcherWinGlibPrivate::~QuailEventDispatcherWinGlibPrivate()
--- a/src/QuailWinGlibEventLoop.h Fri Sep 13 14:11:27 2013 +0100
+++ b/src/QuailWinGlibEventLoop.h Mon Sep 16 16:27:25 2013 +0100
@@ -73,6 +73,7 @@
typedef QHash<int, QSockNot *> QSNDict;
struct WinTimerInfo { // internal timer info
@@ -101,7 +102,6 @@
Q_DECLARE_PUBLIC(QuailEventDispatcherWinGlib)
- QuailEventDispatcherWinGlibPrivate();
QuailEventDispatcherWinGlibPrivate(GMainContext *context = 0);
~QuailEventDispatcherWinGlibPrivate();