Fix event propagation
authorManuel Nickschas <sputnick@quassel-irc.org>
Sun, 17 Oct 2010 19:11:58 +0000 (21:11 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Tue, 19 Oct 2010 21:48:44 +0000 (23:48 +0200)
It sometimes makes sense to deliver the same event to the same object
(but different event handlers), so we shouldn't prevent that. Instead,
make sure that generic handlers are not called if at least one specialized
handler is registered.

src/common/eventmanager.cpp
src/common/eventmanager.h

index 7303ea5..fd3cf9b 100644 (file)
@@ -193,6 +193,8 @@ void EventManager::dispatchEvent(Event *event) {
   QSet<QObject *> ignored;
   uint type = event->type();
 
   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);
   // special handling for numeric IrcEvents
   if((type & ~IrcEventNumericMask) == IrcEventNumeric) {
     ::IrcEventNumeric *numEvent = static_cast< ::IrcEventNumeric *>(event);
@@ -201,19 +203,20 @@ void EventManager::dispatchEvent(Event *event) {
     else {
       int num = numEvent->number();
       if(num > 0) {
     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);
         insertFilters(registeredFilters().value(type + num), filters);
+        checkDupes = true;
       }
     }
   }
 
   // exact type
       }
     }
   }
 
   // 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) {
   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);
   }
 
     insertFilters(registeredFilters().value(type & EventGroupMask), filters);
   }
 
@@ -222,18 +225,18 @@ void EventManager::dispatchEvent(Event *event) {
   for(it = handlers.begin(); it != handlers.end() && !event->isStopped(); ++it) {
     QObject *obj = it->object;
 
   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;
 
       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(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
         continue; // mmmh, event filter told us to not accept
+      }
     }
 
     // finally, deliverance!
     }
 
     // finally, deliverance!
@@ -245,19 +248,27 @@ void EventManager::dispatchEvent(Event *event) {
   delete event;
 }
 
   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 {
   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()) {
       QList<Handler>::iterator it = existing.begin();
       while(it != existing.end()) {
-        if(handler.priority > it->priority)
+        if(checkDupes && handler.object == it->object) {
+          insert = false;
           break;
           break;
+        }
+        if(insertpos == existing.end() && handler.priority > it->priority)
+          insertpos = it;
+
         ++it;
       }
         ++it;
       }
-      existing.insert(it, handler);
+      if(insert)
+        existing.insert(it, handler);
     }
   }
 }
     }
   }
 }
index d4f49c7..bc0a1d4 100644 (file)
@@ -158,7 +158,7 @@ private:
   inline HandlerHash &registeredFilters() { return _registeredFilters; }
 
   //! Add handlers to an existing sorted (by priority) handler list
   inline HandlerHash &registeredFilters() { return _registeredFilters; }
 
   //! Add handlers to an existing sorted (by priority) handler list
-  void insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing);
+  void insertHandlers(const QList<Handler> &newHandlers, QList<Handler> &existing, bool checkDupes = false);
   //! Add filters to an existing filter hash
   void insertFilters(const QList<Handler> &newFilters, QHash<QObject *, Handler> &existing);
 
   //! Add filters to an existing filter hash
   void insertFilters(const QList<Handler> &newFilters, QHash<QObject *, Handler> &existing);