From e7d505e35666393ea965e41c59742f609344e858 Mon Sep 17 00:00:00 2001 From: axis Date: Mon, 1 Nov 2010 17:05:18 +0100 Subject: 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 --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 9 ++-- src/corelib/kernel/qeventdispatcher_symbian_p.h | 4 +- src/gui/kernel/qapplication_s60.cpp | 2 +- src/gui/kernel/qeventdispatcher_s60.cpp | 66 +++++++++++++++++++++++++ src/gui/kernel/qeventdispatcher_s60_p.h | 24 +++++++++ 5 files changed, 100 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index d8cc344..bb9bd01 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -975,9 +975,7 @@ bool QEventDispatcherSymbian::sendPostedEvents() inline void QEventDispatcherSymbian::addDeferredActiveObject(QActiveObject *object) { - if (m_deferredActiveObjects.isEmpty()) { - m_completeDeferredAOs->complete(); - } + queueDeferredActiveObjectsCompletion(); m_deferredActiveObjects.append(object); } @@ -986,6 +984,11 @@ inline void QEventDispatcherSymbian::removeDeferredActiveObject(QActiveObject *o m_deferredActiveObjects.removeAll(object); } +void QEventDispatcherSymbian::queueDeferredActiveObjectsCompletion() +{ + m_completeDeferredAOs->complete(); +} + void QEventDispatcherSymbian::reactivateDeferredActiveObjects() { while (!m_deferredActiveObjects.isEmpty()) { diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index 1486db5..3615996 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -247,7 +247,9 @@ public: void addDeferredActiveObject(QActiveObject *object); void removeDeferredActiveObject(QActiveObject *object); - void reactivateDeferredActiveObjects(); + void queueDeferredActiveObjectsCompletion(); + // Can be overridden to activate local active objects too, but do call baseclass! + virtual void reactivateDeferredActiveObjects(); inline int iterationCount() const { return m_iterationCount; } 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(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(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 #include "qt_s60_p.h" +#include + 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(); -- cgit v0.12 From e6ad4d01e1ff483f5ed81168ffa4500deaf69954 Mon Sep 17 00:00:00 2001 From: axis Date: Mon, 1 Nov 2010 19:38:20 +0100 Subject: Fixed test after the fix to QT-4077. Since the events are balanced now, we need to give them time to get through. RevBy: Trust me --- tests/auto/qinputcontext/tst_qinputcontext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qinputcontext/tst_qinputcontext.cpp b/tests/auto/qinputcontext/tst_qinputcontext.cpp index 7811a53..5a258a9 100644 --- a/tests/auto/qinputcontext/tst_qinputcontext.cpp +++ b/tests/auto/qinputcontext/tst_qinputcontext.cpp @@ -158,8 +158,8 @@ public: } // For some reason, the test fails if using processEvents instead of an event loop - // with a zero timer to quit it, so use the timer. -#define KEY_WAIT 0 + // with a timer to quit it, so use the timer. +#define KEY_WAIT 10 void replay(QWidget *w) { -- cgit v0.12 From 5fffdfb33379210ef37a68ae4257e693f7181c48 Mon Sep 17 00:00:00 2001 From: axis Date: Fri, 5 Nov 2010 16:23:34 +0100 Subject: Revert "Use qtmain.lib to provide entry point for all Symbian applications" This reverts commit 564058a1bbfb1c67bc3d68b7c7a2ebfe83481334. It breaks massively on the symbian/linux-armcc mkspec. Will find a different solution. --- mkspecs/common/symbian/symbian.conf | 3 +-- mkspecs/features/symbian/default_post.prf | 3 +++ mkspecs/features/symbian/symbian_building.prf | 20 +++++++++++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index 6d1f708..decec14 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -79,6 +79,7 @@ QMAKE_LIBS_OPENGL_ES2_QT = -llibglesv2 -lcone -lws32 QMAKE_LIBS_OPENVG = -llibOpenVG -lfbscli -lbitgdi -lgdi QMAKE_LIBS_THREAD = -llibpthread QMAKE_LIBS_COMPAT = +QMAKE_LIBS_QT_ENTRY = -llibcrt0.lib QMAKE_LIBS_S60 = -lavkon -leikcoctl exists($${EPOCROOT}epoc32/include/platform/sgresource/sgimage.h) { @@ -126,8 +127,6 @@ QT_ARCH = symbian load(qt_config) -QMAKE_LIBS_QT_ENTRY = -lqtmain$${QT_LIBINFIX}.lib - # These directories must match what configure uses for QT_INSTALL_PLUGINS and QT_INSTALL_IMPORTS QT_PLUGINS_BASE_DIR = /resource/qt$${QT_LIBINFIX}/plugins QT_IMPORTS_BASE_DIR = /resource/qt/imports diff --git a/mkspecs/features/symbian/default_post.prf b/mkspecs/features/symbian/default_post.prf index 348c366..0564e9b 100644 --- a/mkspecs/features/symbian/default_post.prf +++ b/mkspecs/features/symbian/default_post.prf @@ -3,6 +3,9 @@ load(default_post) contains(TEMPLATE, ".*app") { contains(CONFIG, stdbinary) { QMAKE_LIBS += + } else:contains(QT, gui):contains(CONFIG,qt) { + S60MAIN_LIBS = -leuser + QMAKE_LIBS += -lqtmain$${QT_LIBINFIX}.lib $$S60MAIN_LIBS } else { QMAKE_LIBS += $$QMAKE_LIBS_QT_ENTRY } diff --git a/mkspecs/features/symbian/symbian_building.prf b/mkspecs/features/symbian/symbian_building.prf index 20bc3a3..1a51cb2 100644 --- a/mkspecs/features/symbian/symbian_building.prf +++ b/mkspecs/features/symbian/symbian_building.prf @@ -187,16 +187,26 @@ contains(TEMPLATE, app):!contains(QMAKE_LINK, "^@:.*") { linux-armcc: { QMAKE_LIBS += usrt2_2.lib dfpaeabi.dso dfprvct2_2.dso drtaeabi.dso scppnwdl.dso drtrvct2_2.dso h_t__uf.l\\(switch8.o\\) QMAKE_LIBS += -leexe.lib\\(uc_exe_.o\\) - QMAKE_LIBS -= $$QMAKE_LIBS_QT_ENTRY - QMAKE_LIBS += $$QMAKE_LIBS_QT_ENTRY + contains(CONFIG, "qt"):contains(QT, "gui") { #if linking with QtCore + QMAKE_LIBS -= -lqtmain$${QT_LIBINFIX}.lib + QMAKE_LIBS += -lqtmain$${QT_LIBINFIX}.lib + } else { + QMAKE_LIBS -= -llibcrt0.lib + QMAKE_LIBS += -llibcrt0.lib + } } else :linux-gcce { # notice that we can't merge these as ordering of arguments is important. QMAKE_LIBS += \ -l:eexe.lib \ -l:usrt2_2.lib - modified_entry = $$replace(QMAKE_LIBS_QT_ENTRY, "^-l", "-l:") - QMAKE_LIBS -= $$modified_entry - QMAKE_LIBS += $$modified_entry + contains(CONFIG, "qt"):contains(QT, "gui") { #if linking with QtCore + QMAKE_LIBS -= -l:qtmain$${QT_LIBINFIX}.lib + QMAKE_LIBS += -l:qtmain$${QT_LIBINFIX}.lib + } else { + QMAKE_LIBS -= -l:libcrt0.lib + QMAKE_LIBS -= -l:libcrt0_gcce.lib + QMAKE_LIBS += -l:libcrt0_gcce.lib + } QMAKE_LIBS += \ -l:dfpaeabi.dso \ -l:drtaeabi.dso \ -- cgit v0.12