gui: avoid high CPU usage while waiting for input

- add a timeout to ev_get
- set timeout to 1 second when idle
- delay timeout for 15 frames to keep animation objects working
- stop kinetic scrolling immediately at end of list

Change-Id: I77138055c464b65b71e296f9c7ef63ea06809bc1
diff --git a/gui/gui.cpp b/gui/gui.cpp
index 469beb6..8bdd425 100644
--- a/gui/gui.cpp
+++ b/gui/gui.cpp
@@ -205,7 +205,7 @@
 	}
 
 	// process input events. returns true if any event was received.
-	bool processInput();
+	bool processInput(int timeout_ms);
 
 	void handleDrag();
 
@@ -249,10 +249,10 @@
 InputHandler input_handler;
 
 
-bool InputHandler::processInput()
+bool InputHandler::processInput(int timeout_ms)
 {
 	input_event ev;
-	int ret = ev_get(&ev);
+	int ret = ev_get(&ev, timeout_ms);
 
 	if (ret < 0)
 	{
@@ -546,7 +546,7 @@
 // This special function will return immediately the first time, but then
 // always returns 1/30th of a second (or immediately if called later) from
 // the last time it was called
-static void loopTimer(void)
+static void loopTimer(int input_timeout_ms)
 {
 	static timespec lastCall;
 	static int initialized = 0;
@@ -560,7 +560,7 @@
 
 	do
 	{
-		bool got_event = input_handler.processInput(); // get inputs but don't send drag notices
+		bool got_event = input_handler.processInput(input_timeout_ms); // get inputs but don't send drag notices
 		timespec curTime;
 		clock_gettime(CLOCK_MONOTONIC, &curTime);
 
@@ -583,6 +583,7 @@
 		// We need to sleep some period time microseconds
 		//unsigned int sleepTime = 33333 -(diff.tv_nsec / 1000);
 		//usleep(sleepTime); // removed so we can scan for input
+		input_timeout_ms = 0;
 	} while (1);
 }
 
@@ -615,9 +616,12 @@
 	int has_data = 0;
 #endif
 
+	int input_timeout_ms = 0;
+	int idle_frames = 0;
+
 	for (;;)
 	{
-		loopTimer();
+		loopTimer(input_timeout_ms);
 #ifndef TW_OEM_BUILD
 		if (ors_read_fd > 0) {
 			FD_ZERO(&fdset);
@@ -637,9 +641,13 @@
 
 		if (!gForceRender.get_value())
 		{
-			int ret;
-
-			ret = PageManager::Update();
+			int ret = PageManager::Update();
+			if (ret == 0)
+				++idle_frames;
+			else
+				idle_frames = 0;
+			// due to possible animation objects, we need to delay activating the input timeout
+			input_timeout_ms = idle_frames > 15 ? 1000 : 0;
 
 #ifndef PRINT_RENDER_TIME
 			if (ret > 1)
@@ -663,7 +671,7 @@
 
 				LOGINFO("Render(): %u ms, flip(): %u ms, total: %u ms\n", render_t, flip_t, render_t+flip_t);
 			}
-			else if(ret == 1)
+			else if (ret > 0)
 				flip();
 #endif
 		}
@@ -672,6 +680,7 @@
 			gForceRender.set_value(0);
 			PageManager::Render();
 			flip();
+			input_timeout_ms = 0;
 		}
 
 		blankTimer.checkForTimeout();
@@ -908,7 +917,7 @@
 
 	while (!gGuiConsoleTerminate.get_value())
 	{
-		loopTimer();
+		loopTimer(0);
 
 		if (!gForceRender.get_value())
 		{
diff --git a/gui/scrolllist.cpp b/gui/scrolllist.cpp
index 6143b60..02656c7 100644
--- a/gui/scrolllist.cpp
+++ b/gui/scrolllist.cpp
@@ -632,8 +632,10 @@
 		firstDisplayedItem--;
 		y_offset -= actualItemHeight;
 	}
-	if (firstDisplayedItem == 0 && y_offset > 0)
+	if (firstDisplayedItem == 0 && y_offset > 0) {
 		y_offset = 0; // user kept dragging downward past the top of the list, so always reset the offset to 0 since we can't scroll any further in this direction
+		scrollingSpeed = 0; // stop kinetic scrolling
+	}
 
 	// handle dragging upward, scrolling downward
 	int totalSize = GetItemCount();
@@ -649,9 +651,11 @@
 	if (bottom_offset != 0 && firstDisplayedItem + lines + 1 >= totalSize && y_offset <= bottom_offset) {
 		firstDisplayedItem = totalSize - lines - 1;
 		y_offset = bottom_offset;
+		scrollingSpeed = 0; // stop kinetic scrolling
 	} else if (firstDisplayedItem + lines >= totalSize && y_offset < 0) {
 		firstDisplayedItem = totalSize - lines;
 		y_offset = 0;
+		scrollingSpeed = 0; // stop kinetic scrolling
 	}
 }
 
diff --git a/minuitwrp/events.c b/minuitwrp/events.c
index e2414a4..0309a9a 100644
--- a/minuitwrp/events.c
+++ b/minuitwrp/events.c
@@ -719,7 +719,7 @@
     return 0;
 }
 
-int ev_get(struct input_event *ev)
+int ev_get(struct input_event *ev, int timeout_ms)
 {
     int r;
     unsigned n;
@@ -740,7 +740,7 @@
         lastInputStat = curr;
     }
 
-    r = poll(ev_fds, ev_count, 0);
+    r = poll(ev_fds, ev_count, timeout_ms);
 
     if(r > 0) {
         for(n = 0; n < ev_count; n++) {
diff --git a/minuitwrp/minui.h b/minuitwrp/minui.h
index abebc14..3aa4865 100644
--- a/minuitwrp/minui.h
+++ b/minuitwrp/minui.h
@@ -75,7 +75,7 @@
 
 int ev_init(void);
 void ev_exit(void);
-int ev_get(struct input_event *ev);
+int ev_get(struct input_event *ev, int timeout_ms);
 int ev_has_mouse(void);
 
 // Resources