From 54b1a705c192c1c0afa3c71db393a275f25fc7ca Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Mon, 23 Nov 2015 13:27:02 +0100
Subject: Process multiple events at once inside EventLoop

Test-Information:

Unit and integration tests pass on OS X 10.10.5 and Debian 8.2.
UI remains responsive when transferring a file between two
Swift instances.

Change-Id: I7841347a5d6c55121e02e274a7087a2fc200f879

diff --git a/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm b/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm
index 88da262..2d7c613 100644
--- a/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm
+++ b/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm
@@ -23,7 +23,7 @@ void CocoaEventLoop::handleNextCocoaEvent() {
 		boost::recursive_mutex::scoped_lock lock(isEventInCocoaEventLoopMutex_);
 		isEventInCocoaEventLoop_ = false;
 	}
-	handleNextEvent();
+	handleNextEvents();
 }
 
 void CocoaEventLoop::eventPosted() {
diff --git a/Swiften/EventLoop/DummyEventLoop.cpp b/Swiften/EventLoop/DummyEventLoop.cpp
index 3675ead..45e9af7 100644
--- a/Swiften/EventLoop/DummyEventLoop.cpp
+++ b/Swiften/EventLoop/DummyEventLoop.cpp
@@ -22,7 +22,7 @@ DummyEventLoop::~DummyEventLoop() {
 void DummyEventLoop::processEvents() {
 	while(hasEvents()) {
 		hasEvents_ = false;
-		handleNextEvent();
+		handleNextEvents();
 	}
 }
 
diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp
index d9a9081..b613645 100644
--- a/Swiften/EventLoop/EventLoop.cpp
+++ b/Swiften/EventLoop/EventLoop.cpp
@@ -15,6 +15,7 @@
 #include <boost/optional.hpp>
 #include <boost/thread/locks.hpp>
 
+#include <Swiften/Base/foreach.h>
 #include <Swiften/Base/Log.h>
 
 namespace lambda = boost::lambda;
@@ -40,25 +41,27 @@ EventLoop::EventLoop() : nextEventID_(0) {
 EventLoop::~EventLoop() {
 }
 
-void EventLoop::handleNextEvent() {
+void EventLoop::handleNextEvents() {
+	const int eventsBatched = 100;
 	bool callEventPosted = false;
 	{
 		boost::recursive_mutex::scoped_lock lock(removeEventsMutex_);
 		{
-			boost::optional<Event> nextEvent;
+			std::vector<Event> nextEvents;
 			{
-				boost::recursive_mutex::scoped_lock lock(eventsMutex_);	
-				if (!events_.empty()) {
-					nextEvent = events_.front();
+				boost::recursive_mutex::scoped_lock lock(eventsMutex_);
+				for (int n = 0; ((n < eventsBatched) && !events_.empty()); n++) {
+					nextEvents.push_back(events_.front());
 					events_.pop_front();
 				}
+				callEventPosted = !events_.empty();
 			}
-			callEventPosted = !events_.empty();
-			if (nextEvent) {
-				invokeCallback(nextEvent.get());
+			if (!nextEvents.empty()) {
+				foreach (const Event& event, nextEvents) {
+					invokeCallback(event);
+				}
 			}
 		}
-
 	}
 
 	if (callEventPosted) {
diff --git a/Swiften/EventLoop/EventLoop.h b/Swiften/EventLoop/EventLoop.h
index 54e0fe7..27a8c9c 100644
--- a/Swiften/EventLoop/EventLoop.h
+++ b/Swiften/EventLoop/EventLoop.h
@@ -43,16 +43,17 @@ namespace Swift {
 
 		protected:
 			/**
-			 * The \ref handleNextEvent method is called by an implementation of the abstract \ref EventLoop class
+			 * The \ref handleNextEvents method is called by an implementation of the abstract \ref EventLoop class
 			 * at any point after the virtual \ref eventPosted method has been called.
 			 * This method does not block, except for short-time synchronization.
+			 * It can process multiple events before it reutrns.
 			 */
-			void handleNextEvent();
+			void handleNextEvents();
 
 			/**
 			 * The \ref eventPosted virtual method serves as notification for when events are still available in the queue.
 			 * It is called after the first event is posted to an empty queue or after an event has been handled in
-			 * \ref handleNextEvent and there are still remaining events in the queue.
+			 * \ref handleNextEvents and there are still remaining events in the queue.
 			 */
 			virtual void eventPosted() = 0;
 
diff --git a/Swiften/EventLoop/Qt/QtEventLoop.h b/Swiften/EventLoop/Qt/QtEventLoop.h
index 389b0a7..123b6e8 100644
--- a/Swiften/EventLoop/Qt/QtEventLoop.h
+++ b/Swiften/EventLoop/Qt/QtEventLoop.h
@@ -38,7 +38,7 @@ namespace Swift {
 						boost::recursive_mutex::scoped_lock lock(isEventInQtEventLoopMutex_);	
 						isEventInQtEventLoop_ = false;
 					}
-					handleNextEvent();
+					handleNextEvents();
 					//event->deleteLater(); FIXME: Leak?
 					return true;
 				}
diff --git a/Swiften/EventLoop/SimpleEventLoop.cpp b/Swiften/EventLoop/SimpleEventLoop.cpp
index 0bc06c9..59e799f 100644
--- a/Swiften/EventLoop/SimpleEventLoop.cpp
+++ b/Swiften/EventLoop/SimpleEventLoop.cpp
@@ -36,7 +36,7 @@ void SimpleEventLoop::doRun(bool breakAfterEvents) {
 }
 
 void SimpleEventLoop::runOnce() {
-	handleNextEvent();
+	handleNextEvents();
 }
 
 void SimpleEventLoop::stop() {
diff --git a/Swiften/EventLoop/SingleThreadedEventLoop.cpp b/Swiften/EventLoop/SingleThreadedEventLoop.cpp
index 095b962..d617534 100644
--- a/Swiften/EventLoop/SingleThreadedEventLoop.cpp
+++ b/Swiften/EventLoop/SingleThreadedEventLoop.cpp
@@ -38,7 +38,7 @@ void SingleThreadedEventLoop::handleEvents() {
 		boost::lock_guard<boost::mutex> lock(eventAvailableMutex_);
 		eventAvailable_ = false;
 	}
-	handleNextEvent();
+	handleNextEvents();
 }
 
 void SingleThreadedEventLoop::stop() {
-- 
cgit v0.10.2-6-g49f6