diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
index ca44264..f61c019 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian.cpp
+++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp
@@ -43,7 +43,6 @@
 #include <private/qthread_p.h>
 #include <qcoreapplication.h>
 #include <private/qcoreapplication_p.h>
-#include <qdatetime.h>
 
 #include <unistd.h>
 #include <errno.h>
@@ -630,6 +629,24 @@ void QSocketActiveObject::deleteLater()
     }
 }
 
+#ifdef QT_SYMBIAN_PRIORITY_DROP
+RThread idleDetectorThread;
+TRequestStatus idleUpdateRequest;
+enum QtSymbianIdleStates {QT_SYMBIAN_IDLE_STATE_REQ, QT_SYMBIAN_IDLE_STATE_ACK};
+
+TInt idleDetectorThreadFunc(TAny*)
+{
+    idleDetectorThread.SetPriority(EPriorityAbsoluteBackgroundNormal);
+    for (;;) {
+        User::WaitForRequest(idleUpdateRequest);
+        idleUpdateRequest = QT_SYMBIAN_IDLE_STATE_ACK;
+    }
+}
+
+const int maxBusyTime = 2000; // maximum time we allow idle detector to be blocked before worrying, in milliseconds
+const int baseDelay = 1000; // minimum delay time used when backing off to allow idling, in microseconds
+#endif
+
 QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent)
     : QAbstractEventDispatcher(parent),
       m_activeScheduler(0),
@@ -640,6 +657,15 @@ QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent)
       m_iterationCount(0),
       m_noSocketEvents(false)
 {
+#ifdef QT_SYMBIAN_PRIORITY_DROP
+    m_delay = baseDelay;
+    m_avgEventTime = 0;
+    if (idleDetectorThread.Handle() == RThread().Handle()) {
+        idleUpdateRequest = QT_SYMBIAN_IDLE_STATE_ACK;
+        qt_symbian_throwIfError(idleDetectorThread.Create(_L("IdleDetector"), &idleDetectorThreadFunc, 1024, &User::Allocator(), NULL));
+        idleDetectorThread.Resume();
+    }
+#endif
 }
 
 QEventDispatcherSymbian::~QEventDispatcherSymbian()
@@ -705,23 +731,7 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla
         m_interrupt = false;
 
 #ifdef QT_SYMBIAN_PRIORITY_DROP
-        /*
-         * This QTime variable is used to measure the time it takes to finish
-         * the event loop. If we take too long in the loop, other processes
-         * may be starved and killed. After the first event has completed, we
-         * take the current time, and if the remaining events take longer than
-         * a preset time, we temporarily lower the priority to force a context
-         * switch. For applications that do not take unecessarily long in the
-         * event loop, the priority will not be altered.
-         */
-        QTime time;
-        enum {
-            FirstRun,
-            SubsequentRun,
-            TimeStarted
-        } timeState = FirstRun;
-
-        TProcessPriority priority;
+        QTime eventTimer;
 #endif
 
         while (1) {
@@ -737,10 +747,20 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla
             }
 
 #ifdef QT_SYMBIAN_PRIORITY_DROP
-            if (timeState == SubsequentRun) {
-                time.start();
-                timeState = TimeStarted;
+            if (idleUpdateRequest.Int() == QT_SYMBIAN_IDLE_STATE_ACK) {
+                if (m_delay > baseDelay)
+                    m_delay -= baseDelay;
+                m_lastIdleRequestTimer.start();
+                TRequestStatus *req = &idleUpdateRequest;
+                idleDetectorThread.RequestComplete(req, QT_SYMBIAN_IDLE_STATE_REQ);
+            } else if (m_lastIdleRequestTimer.elapsed() > maxBusyTime) {
+                User::AfterHighRes(m_delay);
+                RDebug::Print(_L("delay = %d  averageEventTime = %d\n"), m_delay, m_avgEventTime);
+                // allow delay to be up to 1/4 of execution time
+                if (idleUpdateRequest.Int() != QT_SYMBIAN_IDLE_STATE_ACK && m_delay*3 < m_avgEventTime)
+                    m_delay += baseDelay;
             }
+            eventTimer.start();
 #endif
 
             TInt error;
@@ -750,6 +770,12 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla
                 CActiveScheduler::Current()->Error(error);
             }
 
+#ifdef QT_SYMBIAN_PRIORITY_DROP
+            int eventDur = eventTimer.elapsed()*1000;
+            // average is calcualted as a 5% decaying exponential average
+            m_avgEventTime = (m_avgEventTime * 95 + eventDur * 5) / 100;
+#endif
+
             if (!handledSymbianEvent) {
                 qFatal("QEventDispatcherSymbian::processEvents(): Caught Symbian stray signal");
             }
@@ -758,20 +784,6 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla
                 break;
             }
             block = false;
-#ifdef QT_SYMBIAN_PRIORITY_DROP
-            if (timeState == TimeStarted && time.elapsed() > 100) {
-                priority = m_processHandle.Priority();
-                m_processHandle.SetPriority(EPriorityBackground);
-                time.start();
-                // Slight chance of race condition in the next lines, but nothing fatal
-                // will happen, just wrong priority.
-                if (m_processHandle.Priority() == EPriorityBackground) {
-                    m_processHandle.SetPriority(priority);
-                }
-            }
-            if (timeState == FirstRun)
-                timeState = SubsequentRun;
-#endif
         };
 
         emit awake();
diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h
index 1ab31cc..f9d21c7 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian_p.h
+++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h
@@ -62,6 +62,7 @@
 #include <qmutex.h>
 #include <qwaitcondition.h>
 #include <qsocketnotifier.h>
+#include <qdatetime.h>
 
 #include <e32base.h>
 
@@ -280,6 +281,9 @@ private:
     QList<QActiveObject *> m_deferredActiveObjects;
 
     RProcess m_processHandle;
+    int m_delay;
+    int m_avgEventTime;
+    QTime m_lastIdleRequestTimer;
 };
 
 #ifdef QT_DEBUG
