Add some const correctness to Network
[quassel.git] / src / common / eventmanager.cpp
index 6c539e7..2709b55 100644 (file)
 #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 {
@@ -116,13 +124,13 @@ void EventManager::registerObject(QObject *object, Priority priority, const QStr
     if(eventType > 0) {
       Handler handler(object, i, priority);
       registeredHandlers()[eventType].append(handler);
-      qDebug() << "Registered event handler for" << methodSignature << "in" << object;
+      //qDebug() << "Registered event handler for" << methodSignature << "in" << object;
     }
     eventType = findEventType(methodSignature, filterPrefix);
     if(eventType > 0) {
       Handler handler(object, i, priority);
       registeredFilters()[eventType].append(handler);
-      qDebug() << "Registered event filterer for" << methodSignature << "in" << object;
+      //qDebug() << "Registered event filterer for" << methodSignature << "in" << object;
     }
   }
 }
@@ -157,29 +165,35 @@ void EventManager::registerEventHandler(QList<EventType> 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<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) {
@@ -193,6 +207,8 @@ 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);
@@ -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<Handler>::const_iterator it = handlers.begin();
-  while(it != handlers.end() && !event->isStopped()) {
+  QList<Handler>::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<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);
     }
   }
 }