#include "event.h"
#include "ircevent.h"
-EventManager::EventManager(QObject *parent) : QObject(parent) {
-
-}
-
-EventManager::~EventManager() {
- // pending events won't be delivered anymore, but we do need to delete them
- qDeleteAll(_eventQueue);
+// ============================================================
+// QueuedEvent
+// ============================================================
+class QueuedQuasselEvent : public QEvent {
+public:
+ QueuedQuasselEvent(Event *event)
+ : QEvent(QEvent::User), event(event) {}
+ Event *event;
+};
+
+// ============================================================
+// EventManager
+// ============================================================
+EventManager::EventManager(QObject *parent)
+ : QObject(parent) {
}
QMetaEnum EventManager::eventEnum() const {
}
}
-// not threadsafe! if we should want that, we need to add a mutexed queue somewhere in this general area.
-void EventManager::sendEvent(Event *event) {
- // qDebug() << "Sending" << event;
- _eventQueue.append(event);
- if(_eventQueue.count() == 1) // we're not currently processing another event
- processEvents();
+void EventManager::postEvent(Event *event) {
+ if(sender() && sender()->thread() != this->thread()) {
+ QueuedQuasselEvent *queuedEvent = new QueuedQuasselEvent(event);
+ QCoreApplication::postEvent(this, queuedEvent);
+ } else {
+ if(_eventQueue.isEmpty())
+ // we're currently not processing events
+ processEvent(event);
+ else
+ _eventQueue.append(event);
+ }
}
void EventManager::customEvent(QEvent *event) {
if(event->type() == QEvent::User) {
- processEvents();
+ QueuedQuasselEvent *queuedEvent = static_cast<QueuedQuasselEvent *>(event);
+ processEvent(queuedEvent->event);
event->accept();
}
}
-void EventManager::processEvents() {
- // we only process one event at a time for now, and let Qt's own event processing come in between
- if(_eventQueue.isEmpty())
- return;
- dispatchEvent(_eventQueue.first());
- _eventQueue.removeFirst();
- if(_eventQueue.count())
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+void EventManager::processEvent(Event *event) {
+ Q_ASSERT(_eventQueue.isEmpty());
+ dispatchEvent(event);
+ // dispatching the event might cause new events to be generated. we process those afterwards.
+ while(!_eventQueue.isEmpty()) {
+ dispatchEvent(_eventQueue.first());
+ _eventQueue.removeFirst();
+ }
}
void EventManager::dispatchEvent(Event *event) {
QSet<QObject *> ignored;
uint type = event->type();
+ bool checkDupes = false;
+
// special handling for numeric IrcEvents
if((type & ~IrcEventNumericMask) == IrcEventNumeric) {
::IrcEventNumeric *numEvent = static_cast< ::IrcEventNumeric *>(event);
else {
int num = numEvent->number();
if(num > 0) {
- insertHandlers(registeredHandlers().value(type + num), handlers);
+ insertHandlers(registeredHandlers().value(type + num), handlers, false);
insertFilters(registeredFilters().value(type + num), filters);
+ checkDupes = true;
}
}
}
// exact type
- insertHandlers(registeredHandlers().value(type), handlers);
+ insertHandlers(registeredHandlers().value(type), handlers, checkDupes);
insertFilters(registeredFilters().value(type), filters);
// check if we have a generic handler for the event group
if((type & EventGroupMask) != type) {
- insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers);
+ insertHandlers(registeredHandlers().value(type & EventGroupMask), handlers, true);
insertFilters(registeredFilters().value(type & EventGroupMask), filters);
}
for(it = handlers.begin(); it != handlers.end() && !event->isStopped(); ++it) {
QObject *obj = it->object;
- if(ignored.contains(obj)) // we only deliver an event once to any given object
+ if(ignored.contains(obj)) // object has filtered the event
continue;
- ignored.insert(obj);
-
if(filters.contains(obj)) { // we have a filter, so let's check if we want to deliver the event
Handler filter = filters.value(obj);
bool result = false;
void *param[] = {Q_RETURN_ARG(bool, result).data(), Q_ARG(Event *, event).data() };
obj->qt_metacall(QMetaObject::InvokeMetaMethod, filter.methodIndex, param);
- if(!result)
+ if(!result) {
+ ignored.insert(obj);
continue; // mmmh, event filter told us to not accept
+ }
}
// finally, deliverance!
delete event;
}
-void EventManager::insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing) {
+void EventManager::insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing, bool checkDupes) {
foreach(const Handler &handler, newHandlers) {
if(existing.isEmpty())
existing.append(handler);
else {
- // need to insert it at the proper position
+ // need to insert it at the proper position, but only if we don't yet have a handler for this event and object!
+ bool insert = true;
+ QList<Handler>::iterator insertpos = existing.end();
QList<Handler>::iterator it = existing.begin();
while(it != existing.end()) {
- if(handler.priority > it->priority)
+ if(checkDupes && handler.object == it->object) {
+ insert = false;
break;
+ }
+ if(insertpos == existing.end() && handler.priority > it->priority)
+ insertpos = it;
+
++it;
}
- existing.insert(it, handler);
+ if(insert)
+ existing.insert(it, handler);
}
}
}