diff options
author | axis <qt-info@nokia.com> | 2010-11-01 16:05:18 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2010-11-05 09:24:01 (GMT) |
commit | e7d505e35666393ea965e41c59742f609344e858 (patch) | |
tree | 688166201683a332ef81d4c8a17d1cd4c9c398f1 /src/gui | |
parent | 55497edc83121317078d62083a835f2b794b37e4 (diff) | |
download | Qt-e7d505e35666393ea965e41c59742f609344e858.zip Qt-e7d505e35666393ea965e41c59742f609344e858.tar.gz Qt-e7d505e35666393ea965e41c59742f609344e858.tar.bz2 |
Fixed event starvation with pointer events on Symbian.
The CEikonEnv active object is used by Symbian to indicate that new
window server events are available, in this case pointer events.
Since this object was being controlled by Symbian, it was not subject
to Qt's round robin queue. In a case where the event handler for the
pointer event would take very long, it was possible for the active
object to be completed again before the previous handler was
finished, causing it to be called in a loop.
This was fixed by making a new Qt-owned class as a subclass of
CEikonEnv, and in its RunL, make sure that the object follows the
round-robin queue.
Because the round robin code is located in a subclass of CEikonEnv
that we own, the fix will have no effect if Qt is loaded after the
Eikon framework (such as a Qt plugin in a non-Qt app).
Task: QT-4077
RevBy: mread
AutoTest: N/A, system events
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/kernel/qapplication_s60.cpp | 2 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_s60.cpp | 66 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_s60_p.h | 24 |
3 files changed, 91 insertions, 1 deletions
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 5ff2fd4..7c2ab29 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1425,7 +1425,7 @@ void qt_init(QApplicationPrivate * /* priv */, int) TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine); // After this construction, CEikonEnv will be available from CEikonEnv::Static(). // (much like our qApp). - CEikonEnv* coe = new CEikonEnv; + QtEikonEnv* coe = new QtEikonEnv; //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there. if(err == KErrNone) TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine)); diff --git a/src/gui/kernel/qeventdispatcher_s60.cpp b/src/gui/kernel/qeventdispatcher_s60.cpp index bc787b8..77ebd0d 100644 --- a/src/gui/kernel/qeventdispatcher_s60.cpp +++ b/src/gui/kernel/qeventdispatcher_s60.cpp @@ -45,6 +45,62 @@ QT_BEGIN_NAMESPACE +QtEikonEnv::QtEikonEnv() + : m_lastIterationCount(0) + , m_savedStatusCode(KRequestPending) + , m_hasAlreadyRun(false) +{ +} + +QtEikonEnv::~QtEikonEnv() +{ +} + +void QtEikonEnv::RunL() +{ + QEventDispatcherS60 *dispatcher = qobject_cast<QEventDispatcherS60 *>(QAbstractEventDispatcher::instance()); + if (!dispatcher) { + CEikonEnv::RunL(); + return; + } + + if (m_lastIterationCount != dispatcher->iterationCount()) { + m_hasAlreadyRun = false; + m_lastIterationCount = dispatcher->iterationCount(); + } + + if (m_hasAlreadyRun) { + // Fool the active scheduler into believing we are still waiting for events. + // The window server thinks we are not, however. + m_savedStatusCode = iStatus.Int(); + iStatus = KRequestPending; + SetActive(); + dispatcher->queueDeferredActiveObjectsCompletion(); + } else { + m_hasAlreadyRun = true; + CEikonEnv::RunL(); + } +} + +void QtEikonEnv::DoCancel() +{ + complete(); + + CEikonEnv::DoCancel(); +} + +void QtEikonEnv::complete() +{ + if (m_hasAlreadyRun) { + if (m_savedStatusCode != KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, m_savedStatusCode); + m_savedStatusCode = KRequestPending; + } + m_hasAlreadyRun = false; + } +} + QEventDispatcherS60::QEventDispatcherS60(QObject *parent) : QEventDispatcherSymbian(parent), m_noInputEvents(false) @@ -127,4 +183,14 @@ void QEventDispatcherS60::removeInputEventsForWidget(QObject *object) } } +// reimpl +void QEventDispatcherS60::reactivateDeferredActiveObjects() +{ + if (S60->qtOwnsS60Environment) { + static_cast<QtEikonEnv *>(CCoeEnv::Static())->complete(); + } + + QEventDispatcherSymbian::reactivateDeferredActiveObjects(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qeventdispatcher_s60_p.h b/src/gui/kernel/qeventdispatcher_s60_p.h index d2f327c..c14fef0 100644 --- a/src/gui/kernel/qeventdispatcher_s60_p.h +++ b/src/gui/kernel/qeventdispatcher_s60_p.h @@ -56,8 +56,30 @@ #include <private/qeventdispatcher_symbian_p.h> #include "qt_s60_p.h" +#include <eikenv.h> + QT_BEGIN_NAMESPACE +class QEventDispatcherS60; + +class QtEikonEnv : public CEikonEnv +{ +public: + QtEikonEnv(); + ~QtEikonEnv(); + + // from CActive. + void RunL(); + void DoCancel(); + + void complete(); + +private: + int m_lastIterationCount; + TInt m_savedStatusCode; + bool m_hasAlreadyRun; +}; + class Q_GUI_EXPORT QEventDispatcherS60 : public QEventDispatcherSymbian { Q_OBJECT @@ -73,6 +95,8 @@ public: void saveInputEvent(QSymbianControl *control, QWidget *widget, QInputEvent *event); + void reactivateDeferredActiveObjects(); + private: bool sendDeferredInputEvents(); |