Changing the behavior how Quassel Events are processed.
authorMarcus Eggenberger <egs@quassel-irc.org>
Tue, 14 Jun 2011 22:45:39 +0000 (00:45 +0200)
committerMarcus Eggenberger <egs@quassel-irc.org>
Tue, 14 Jun 2011 22:45:39 +0000 (00:45 +0200)
They are no longer scheduled individualy but processed immediately
when they are generated. this should prohibit quassel from messing
with the space time continuum.

14 files changed:
src/common/eventmanager.cpp
src/common/eventmanager.h
src/core/corenetwork.cpp
src/core/corenetwork.h
src/core/coresession.cpp
src/core/coresession.h
src/core/coresessioneventprocessor.cpp
src/core/coresessioneventprocessor.h
src/core/ctcpparser.cpp
src/core/ctcpparser.h
src/core/eventstringifier.cpp
src/core/eventstringifier.h
src/core/ircparser.cpp
src/core/ircparser.h

index 3fe581c..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 {
@@ -157,31 +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));
-  else
-    emit eventQueueEmptied();
+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) {
index 9b6e5a0..e01b594 100644 (file)
@@ -111,7 +111,6 @@ public:
   };
 
   EventManager(QObject *parent = 0);
-  virtual ~EventManager();
 
   EventType eventTypeByName(const QString &name) const;
   EventType eventGroupByName(const QString &name) const;
@@ -133,13 +132,9 @@ public slots:
   //! Send an event to the registered handlers
   /**
     The EventManager takes ownership of the event and will delete it once it's processed.
-    NOTE: This method is not threadsafe!
     @param event The event to be dispatched
    */
-  void sendEvent(Event *event);
-
-signals:
-  void eventQueueEmptied();
+  void postEvent(Event *event);
 
 protected:
   virtual void customEvent(QEvent *event);
@@ -172,7 +167,7 @@ private:
 
   int findEventType(const QString &methodSignature, const QString &methodPrefix) const;
 
-  void processEvents();
+  void processEvent(Event *event);
   void dispatchEvent(Event *event);
 
   //! @return the EventType enum
@@ -181,7 +176,6 @@ private:
   HandlerHash _registeredHandlers;
   HandlerHash _registeredFilters;
   mutable QMetaEnum _enum;
-
   QList<Event *> _eventQueue;
 };
 
index 534199e..d18ddca 100644 (file)
@@ -77,6 +77,7 @@ CoreNetwork::CoreNetwork(const NetworkId &networkid, CoreSession *session)
   connect(&socket, SIGNAL(encrypted()), this, SLOT(socketInitialized()));
   connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
 #endif
+  connect(this, SIGNAL(newEvent(Event *)), coreSession()->eventManager(), SLOT(postEvent(Event *)));
 }
 
 CoreNetwork::~CoreNetwork() {
@@ -330,7 +331,7 @@ void CoreNetwork::socketHasData() {
 #else
     event->setTimestamp(QDateTime::currentDateTime().toUTC());
 #endif
-    coreSession()->eventManager()->sendEvent(event);
+    emit newEvent(event);
   }
 }
 
index f4744d9..c1f96f2 100644 (file)
@@ -43,6 +43,7 @@
 class CoreIdentity;
 class CoreUserInputHandler;
 class CoreIgnoreListManager;
+class Event;
 
 class CoreNetwork : public Network {
   SYNCABLE_OBJECT
@@ -144,6 +145,8 @@ signals:
   void quitRequested(NetworkId networkId);
   void sslErrors(const QVariant &errorData);
 
+  void newEvent(Event *event);
+
 protected:
   inline virtual IrcChannel *ircChannelFactory(const QString &channelname) { return new CoreIrcChannel(channelname, this); }
   inline virtual IrcUser *ircUserFactory(const QString &hostmask) { return new CoreIrcUser(hostmask, this); }
index 0173a95..3fd539e 100644 (file)
@@ -68,6 +68,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     _ctcpParser(new CtcpParser(this)),
     _ircParser(new IrcParser(this)),
     scriptEngine(new QScriptEngine(this)),
+    _processMessages(false),
     _ignoreListManager(this)
 {
   SignalProxy *p = signalProxy();
@@ -96,7 +97,6 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
   loadSettings();
   initScriptEngine();
 
-  connect(eventManager(), SIGNAL(eventQueueEmptied()), SLOT(processMessages()));
   eventManager()->registerObject(ircParser(), EventManager::NormalPriority);
   eventManager()->registerObject(sessionEventProcessor(), EventManager::HighPriority); // needs to process events *before* the stringifier!
   eventManager()->registerObject(ctcpParser(), EventManager::NormalPriority);
@@ -223,9 +223,6 @@ void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg) {
   CoreNetwork *net = network(bufinfo.networkId());
   if(net) {
     net->userInput(bufinfo, msg);
-    // FIXME as soon as user input is event-based
-    // until then, user input doesn't trigger a message queue flush!
-    processMessages();
   } else {
     qWarning() << "Trying to send to unconnected network:" << msg;
   }
@@ -250,6 +247,10 @@ void CoreSession::recvMessageFromServer(NetworkId networkId, Message::Type type,
     return;
 
   _messageQueue << rawMsg;
+  if(!_processMessages) {
+    _processMessages = true;
+    QCoreApplication::postEvent(this, new ProcessMessagesEvent());
+  }
 }
 
 void CoreSession::recvStatusMsgFromServer(QString msg) {
@@ -270,10 +271,15 @@ QList<BufferInfo> CoreSession::buffers() const {
   return Core::requestBuffers(user());
 }
 
-void CoreSession::processMessages() {
-  if(_messageQueue.isEmpty())
+void CoreSession::customEvent(QEvent *event) {
+  if(event->type() != QEvent::User)
     return;
 
+  processMessages();
+  event->accept();
+}
+
+void CoreSession::processMessages() {
   if(_messageQueue.count() == 1) {
     const RawMessage &rawMsg = _messageQueue.first();
     bool createBuffer = !(rawMsg.flags & Message::Redirected);
@@ -329,6 +335,7 @@ void CoreSession::processMessages() {
       emit displayMsg(messages[i]);
     }
   }
+  _processMessages = false;
   _messageQueue.clear();
 }
 
index 9d8ba55..8b4305e 100644 (file)
@@ -150,12 +150,14 @@ signals:
   void networkRemoved(NetworkId);
   void networkDisconnected(NetworkId);
 
+protected:
+  virtual void customEvent(QEvent *event);
+
 private slots:
   void removeClient(QIODevice *dev);
 
   void recvStatusMsgFromServer(QString msg);
   void recvMessageFromServer(NetworkId networkId, Message::Type, BufferInfo::Type, const QString &target, const QString &text, const QString &sender = "", Message::Flags flags = Message::None);
-  void processMessages();
 
   void destroyNetwork(NetworkId);
 
@@ -169,6 +171,8 @@ private slots:
   void saveSessionState() const;
 
 private:
+  void processMessages();
+
   void loadSettings();
   void initScriptEngine();
 
@@ -200,6 +204,7 @@ private:
   QScriptEngine *scriptEngine;
 
   QList<RawMessage> _messageQueue;
+  bool _processMessages;
   CoreIgnoreListManager _ignoreListManager;
 };
 
index 59565a0..2eb7f6d 100644 (file)
@@ -35,6 +35,7 @@ CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session)
   _coreSession(session)
 {
   connect(coreSession(), SIGNAL(networkDisconnected(NetworkId)), this, SLOT(destroyNetsplits(NetworkId)));
+  connect(this, SIGNAL(newEvent(Event *)), coreSession()->eventManager(), SLOT(postEvent(Event *)));
 }
 
 bool CoreSessionEventProcessor::checkParamCount(IrcEvent *e, int minParams) {
@@ -63,7 +64,7 @@ void CoreSessionEventProcessor::tryNextNick(NetworkEvent *e, const QString &errn
       MessageEvent *msgEvent = new MessageEvent(Message::Error, e->network(),
                                                 tr("No free and valid nicks in nicklist found. use: /nick <othernick> to continue"),
                                                 QString(), QString(), Message::None, e->timestamp());
-      coreSession()->eventManager()->sendEvent(msgEvent);
+      emit newEvent(msgEvent);
       return;
     } else {
       nextNick = errnick + "_";
@@ -747,12 +748,12 @@ void CoreSessionEventProcessor::handleNetsplitJoin(Network *net,
 
   ircChannel->joinIrcUsers(ircUsers, newModes);
   NetworkSplitEvent *event = new NetworkSplitEvent(EventManager::NetworkSplitJoin, net, channel, newUsers, quitMessage);
-  coreSession()->eventManager()->sendEvent(event);
+  emit newEvent(event);
 }
 
 void CoreSessionEventProcessor::handleNetsplitQuit(Network *net, const QString &channel, const QStringList &users, const QString& quitMessage) {
   NetworkSplitEvent *event = new NetworkSplitEvent(EventManager::NetworkSplitQuit, net, channel, users, quitMessage);
-  coreSession()->eventManager()->sendEvent(event);
+  emit newEvent(event);
   foreach(QString user, users) {
     IrcUser *iu = net->ircUser(nickFromMask(user));
     if(iu)
@@ -784,7 +785,7 @@ void CoreSessionEventProcessor::handleEarlyNetsplitJoin(Network *net, const QStr
   ircChannel->joinIrcUsers(ircUsers, newModes);
   foreach(NetworkEvent *event, events) {
     event->setFlag(EventManager::Fake); // ignore this in here!
-    coreSession()->eventManager()->sendEvent(event);
+    emit newEvent(event);
   }
 }
 
index e0219e3..b2ba39c 100644 (file)
@@ -94,6 +94,9 @@ public:
   Q_INVOKABLE void handleCtcpVersion(CtcpEvent *event);
   Q_INVOKABLE void defaultHandler(const QString &ctcpCmd, CtcpEvent *event);
 
+signals:
+  void newEvent(Event *event);
+
 protected:
   bool checkParamCount(IrcEvent *event, int minParams);
   inline CoreNetwork *coreNetwork(NetworkEvent *e) const { return qobject_cast<CoreNetwork *>(e->network()); }
index 1aa8c0e..f4177c6 100644 (file)
@@ -39,6 +39,8 @@ CtcpParser::CtcpParser(CoreSession *coreSession, QObject *parent)
   QByteArray XQUOTE = QByteArray("\134");
   _ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE;
   _ctcpXDelimDequoteHash[XQUOTE + QByteArray("a")] = XDELIM;
+
+  connect(this, SIGNAL(newEvent(Event *)), _coreSession->eventManager(), SLOT(postEvent(Event *)));
 }
 
 void CtcpParser::displayMsg(NetworkEvent *event, Message::Type msgType, const QString &msg, const QString &sender,
@@ -49,7 +51,7 @@ void CtcpParser::displayMsg(NetworkEvent *event, Message::Type msgType, const QS
   MessageEvent *msgEvent = new MessageEvent(msgType, event->network(), msg, sender, target, msgFlags);
   msgEvent->setTimestamp(event->timestamp());
 
-  coreSession()->eventManager()->sendEvent(msgEvent);
+  emit newEvent(msgEvent);
 }
 
 QByteArray CtcpParser::lowLevelQuote(const QByteArray &message) {
@@ -193,7 +195,7 @@ void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype) {
                                           ctcptype, "INVALID", QString(), e->timestamp(), uuid);
     ctcpEvents << flushEvent;
     foreach(CtcpEvent *event, ctcpEvents) {
-      coreSession()->eventManager()->sendEvent(event);
+      emit newEvent(event);
     }
   }
 
index 1091596..e68e737 100644 (file)
@@ -46,6 +46,9 @@ public:
 
   Q_INVOKABLE void sendCtcpEvent(CtcpEvent *event);
 
+signals:
+  void newEvent(Event *event);
+
 protected:
   inline CoreNetwork *coreNetwork(NetworkEvent *e) const { return qobject_cast<CoreNetwork *>(e->network()); }
 
index 1b817af..7276edf 100644 (file)
@@ -28,7 +28,7 @@ EventStringifier::EventStringifier(CoreSession *parent) : BasicHandler("handleCt
   _coreSession(parent),
   _whois(false)
 {
-
+  connect(this, SIGNAL(newMessageEvent(Event *)), coreSession()->eventManager(), SLOT(postEvent(Event *)));
 }
 
 void EventStringifier::displayMsg(NetworkEvent *event, Message::Type msgType, const QString &msg, const QString &sender,
@@ -37,7 +37,8 @@ void EventStringifier::displayMsg(NetworkEvent *event, Message::Type msgType, co
     return;
 
   MessageEvent *msgEvent = createMessageEvent(event, msgType, msg, sender, target, msgFlags);
-  sendMessageEvent(msgEvent);
+  //sendMessageEvent(msgEvent);
+  emit newMessageEvent(msgEvent);
 }
 
 MessageEvent *EventStringifier::createMessageEvent(NetworkEvent *event, Message::Type msgType, const QString &msg, const QString &sender,
@@ -47,10 +48,6 @@ MessageEvent *EventStringifier::createMessageEvent(NetworkEvent *event, Message:
   return msgEvent;
 }
 
-void EventStringifier::sendMessageEvent(MessageEvent *event) {
-  coreSession()->eventManager()->sendEvent(event);
-}
-
 bool EventStringifier::checkParamCount(IrcEvent *e, int minParams) {
   if(e->params().count() < minParams) {
     if(e->type() == EventManager::IrcEventNumeric) {
index 1c317c8..69d11c3 100644 (file)
@@ -109,9 +109,11 @@ public slots:
                   const QString &target = QString(),
                   Message::Flags msgFlags = Message::None);
 
+signals:
+  void newMessageEvent(Event *event);
+
 private:
   bool checkParamCount(IrcEvent *event, int minParams);
-  void sendMessageEvent(MessageEvent *event);
 
   CoreSession *_coreSession;
   bool _whois;
index b372e35..605dd2e 100644 (file)
@@ -34,7 +34,7 @@ IrcParser::IrcParser(CoreSession *session) :
   QObject(session),
   _coreSession(session)
 {
-
+  connect(this, SIGNAL(newEvent(Event *)), coreSession()->eventManager(), SLOT(postEvent(Event *)));
 }
 
 bool IrcParser::checkParamCount(const QString &cmd, const QList<QByteArray> &params, int minParams) {
@@ -136,16 +136,18 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) {
   QList<Event *> events;
   EventManager::EventType type = EventManager::Invalid;
 
-  // numeric replies have the target as first param (RFC 2812 - 2.4). this is usually our own nick. Remove this!
   uint num = cmd.toUInt();
   if(num > 0) {
+    // numeric reply
     if(params.count() == 0) {
       qWarning() << "Message received from server violates RFC and is ignored!" << msg;
       return;
     }
+    // numeric replies have the target as first param (RFC 2812 - 2.4). this is usually our own nick. Remove this!
     target = net->serverDecode(params.takeFirst());
     type = EventManager::IrcEventNumeric;
   } else {
+    // any other irc command
     QString typeName = QLatin1String("IrcEvent") + cmd.at(0).toUpper() + cmd.mid(1).toLower();
     type = eventManager()->eventTypeByName(typeName);
     if(type == EventManager::Invalid) {
@@ -300,6 +302,6 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) {
   }
 
   foreach(Event *event, events) {
-    coreSession()->eventManager()->sendEvent(event);
+    emit newEvent(event);
   }
 }
index c16c898..402e656 100644 (file)
@@ -37,6 +37,9 @@ public:
   inline CoreSession *coreSession() const { return _coreSession; }
   inline EventManager *eventManager() const { return coreSession()->eventManager(); }
 
+signals:
+  void newEvent(Event *);
+
 protected:
   Q_INVOKABLE void processNetworkIncoming(NetworkDataEvent *e);