X-Git-Url: https://git.quassel-irc.org/?a=blobdiff_plain;f=src%2Fcommon%2Feventmanager.cpp;h=2709b557fd338d718ee866af6fd59824f3b857fb;hb=7fdaa5c9df2e632685ef2d8d0177ac22b7145a6f;hp=36682b06510304eaa9665127a71682185135c41c;hpb=bd6311ec1d07e4daf082b5f752ef6b46d7808430;p=quassel.git diff --git a/src/common/eventmanager.cpp b/src/common/eventmanager.cpp index 36682b06..2709b557 100644 --- a/src/common/eventmanager.cpp +++ b/src/common/eventmanager.cpp @@ -27,13 +27,21 @@ #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 { @@ -157,29 +165,35 @@ void EventManager::registerEventHandler(QList events, QObject *object } } -// 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(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) { @@ -193,6 +207,8 @@ void EventManager::dispatchEvent(Event *event) { QSet ignored; uint type = event->type(); + bool checkDupes = false; + // special handling for numeric IrcEvents if((type & ~IrcEventNumericMask) == IrcEventNumeric) { ::IrcEventNumeric *numEvent = static_cast< ::IrcEventNumeric *>(event); @@ -201,28 +217,29 @@ void EventManager::dispatchEvent(Event *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); } // now dispatch the event - QList::const_iterator it = handlers.begin(); - while(it != handlers.end() && !event->isStopped()) { + QList::const_iterator it; + 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; if(filters.contains(obj)) { // we have a filter, so let's check if we want to deliver the event @@ -230,35 +247,42 @@ void EventManager::dispatchEvent(Event *event) { bool result = false; void *param[] = {Q_RETURN_ARG(bool, result).data(), Q_ARG(Event *, event).data() }; obj->qt_metacall(QMetaObject::InvokeMetaMethod, filter.methodIndex, param); - ignored.insert(obj); // don't try to deliver the event again either way - if(!result) + if(!result) { + ignored.insert(obj); continue; // mmmh, event filter told us to not accept + } } // finally, deliverance! void *param[] = {0, Q_ARG(Event *, event).data() }; obj->qt_metacall(QMetaObject::InvokeMetaMethod, it->methodIndex, param); - - ++it; } // that's it delete event; } -void EventManager::insertHandlers(const QList &newHandlers, QList &existing) { +void EventManager::insertHandlers(const QList &newHandlers, QList &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::iterator insertpos = existing.end(); QList::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); } } }