src/gui/kernel/qapplication_s60.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/kernel/qapplication_s60.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1841 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication_p.h"
+#include "qsessionmanager.h"
+#include "qevent.h"
+#include "qsymbianevent.h"
+#include "qeventdispatcher_s60_p.h"
+#include "qwidget.h"
+#include "qdesktopwidget.h"
+#include "private/qbackingstore_p.h"
+#include "qt_s60_p.h"
+#include "private/qevent_p.h"
+#include "qstring.h"
+#include "qdebug.h"
+#include "qimage.h"
+#include "private/qkeymapper_p.h"
+#include "private/qfont_p.h"
+#ifndef QT_NO_STYLE_S60
+#include "private/qs60style_p.h"
+#endif
+#include "private/qwindowsurface_s60_p.h"
+#include "qpaintengine.h"
+#include "private/qmenubar_p.h"
+#include "private/qsoftkeymanager_p.h"
+
+#include "apgwgnam.h" // For CApaWindowGroupName
+#include <MdaAudioTonePlayer.h>     // For CMdaAudioToneUtility
+
+#if defined(Q_WS_S60)
+# if !defined(QT_NO_IM)
+#  include "qinputcontext.h"
+#  include <private/qcoefepinputcontext_p.h>
+# endif
+# include <private/qs60mainapplication_p.h>
+#endif
+
+#include "private/qstylesheetstyle_p.h"
+
+#include <hal.h>
+#include <hal_data.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(QT_DEBUG)
+static bool        appNoGrab        = false;        // Grabbing enabled
+#endif
+static bool        app_do_modal        = false;        // modal mode
+Q_GLOBAL_STATIC(QS60Data, qt_s60Data);
+
+extern bool qt_sendSpontaneousEvent(QObject*,QEvent*);
+extern QWidgetList *qt_modal_stack;              // stack of modal widgets
+extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
+
+QWidget *qt_button_down = 0;                     // widget got last button-down
+
+QSymbianControl *QSymbianControl::lastFocusedControl = 0;
+
+QS60Data* qGlobalS60Data()
+{
+    return qt_s60Data();
+}
+
+bool qt_nograb()                                // application no-grab option
+{
+#if defined(QT_DEBUG)
+    return appNoGrab;
+#else
+    return false;
+#endif
+}
+
+// Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument
+class QS60Beep : public CBase, public MMdaAudioToneObserver
+{
+public:
+    static QS60Beep* NewL(TInt aFrequency,  TTimeIntervalMicroSeconds iDuration);
+    void Play();
+    ~QS60Beep();
+private:
+    void ConstructL(TInt aFrequency,  TTimeIntervalMicroSeconds iDuration);
+    void MatoPrepareComplete(TInt aError);
+    void MatoPlayComplete(TInt aError);
+private:
+    typedef enum
+        {
+        EBeepNotPrepared,
+        EBeepPrepared,
+        EBeepPlaying
+        } TBeepState;
+private:
+    CMdaAudioToneUtility* iToneUtil;
+    TBeepState iState;
+    TInt iFrequency;
+    TTimeIntervalMicroSeconds iDuration;
+};
+
+QS60Beep::~QS60Beep()
+{
+    delete iToneUtil;
+}
+
+QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
+{
+    QS60Beep* self=new (ELeave) QS60Beep();
+    CleanupStack::PushL(self);
+    self->ConstructL(aFrequency, aDuration);
+    CleanupStack::Pop();
+    return self;
+};
+
+void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
+{
+    iToneUtil=CMdaAudioToneUtility::NewL(*this);
+    iState=EBeepNotPrepared;
+    iFrequency=aFrequency;
+    iDuration=aDuration;
+    iToneUtil->PrepareToPlayTone(iFrequency,iDuration);
+}
+
+void QS60Beep::Play()
+{
+    if (iState != EBeepNotPrepared) {
+        if (iState == EBeepPlaying) {
+            iToneUtil->CancelPlay();
+            iState = EBeepPrepared;
+        }
+    }
+
+    iToneUtil->Play();
+    iState = EBeepPlaying;
+}
+
+void QS60Beep::MatoPrepareComplete(TInt aError)
+{
+    if (aError == KErrNone) {
+        iState = EBeepPrepared;
+    }
+}
+
+void QS60Beep::MatoPlayComplete(TInt aError)
+{
+    Q_UNUSED(aError);
+    iState=EBeepPrepared;
+}
+
+
+QHash<TInt, TUint> QApplicationPrivate::scanCodeCache;
+
+static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers)
+{
+    Qt::KeyboardModifiers result = Qt::NoModifier;
+
+    if (s60Modifiers & EModifierKeypad)
+        result |= Qt::KeypadModifier;
+    if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift
+            || s60Modifiers & EModifierRightShift)
+        result |= Qt::ShiftModifier;
+    if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl
+            || s60Modifiers & EModifierRightCtrl)
+        result |= Qt::ControlModifier;
+    if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt
+            || s60Modifiers & EModifierRightAlt)
+        result |= Qt::AltModifier;
+
+    return result;
+}
+
+static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent)
+{
+    switch (pEvent->iType) {
+    case TPointerEvent::EButton1Down:
+        *type = QEvent::MouseButtonPress;
+        *button = Qt::LeftButton;
+        break;
+    case TPointerEvent::EButton1Up:
+        *type = QEvent::MouseButtonRelease;
+        *button = Qt::LeftButton;
+        break;
+    case TPointerEvent::EButton2Down:
+        *type = QEvent::MouseButtonPress;
+        *button = Qt::MidButton;
+        break;
+    case TPointerEvent::EButton2Up:
+        *type = QEvent::MouseButtonRelease;
+        *button = Qt::MidButton;
+        break;
+    case TPointerEvent::EButton3Down:
+        *type = QEvent::MouseButtonPress;
+        *button = Qt::RightButton;
+        break;
+    case TPointerEvent::EButton3Up:
+        *type = QEvent::MouseButtonRelease;
+        *button = Qt::RightButton;
+        break;
+    case TPointerEvent::EDrag:
+        *type = QEvent::MouseMove;
+        *button = Qt::NoButton;
+        break;
+    case TPointerEvent::EMove:
+        // Qt makes no distinction between move and drag
+        *type = QEvent::MouseMove;
+        *button = Qt::NoButton;
+        break;
+    default:
+        *type = QEvent::None;
+        *button = Qt::NoButton;
+        break;
+    }
+    if (pEvent->iModifiers & EModifierDoubleClick){
+        *type = QEvent::MouseButtonDblClick;
+    }
+
+    if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick)
+        QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button);
+    else if (*type == QEvent::MouseButtonRelease)
+        QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button));
+
+    QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask;
+}
+
+//### Can be replaced with CAknLongTapDetector if animation is required.
+//NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,.
+//also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used.
+class QLongTapTimer : public CTimer
+{
+public:
+    static QLongTapTimer* NewL(QAbstractLongTapObserver *observer);
+    QLongTapTimer(QAbstractLongTapObserver *observer);
+    void ConstructL();
+public:
+    void PointerEventL(const TPointerEvent &event);
+    void RunL();
+protected:
+private:
+    QAbstractLongTapObserver *m_observer;
+    TPointerEvent m_event;
+    QPoint m_pressedCoordinates;
+    int m_dragDistance;
+};
+
+QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer)
+{
+    QLongTapTimer* self = new QLongTapTimer(observer);
+    self->ConstructL();
+    return self;
+}
+void QLongTapTimer::ConstructL()
+{
+    CTimer::ConstructL();
+}
+
+QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh)
+{
+    m_observer = observer;
+    m_dragDistance = qApp->startDragDistance();
+    CActiveScheduler::Add(this);
+}
+
+void QLongTapTimer::PointerEventL(const TPointerEvent& event)
+{
+    if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat)
+    {
+        QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates);
+        if (diff.manhattanLength() < m_dragDistance)
+            return;
+    }
+    Cancel();
+    m_event = event;
+    if (event.iType == TPointerEvent::EButton1Down)
+    {
+        m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY);
+        // must be same as KLongTapDelay in aknlongtapdetector.h
+        After(800000);
+    }
+}
+void QLongTapTimer::RunL()
+{
+    if (m_observer)
+        m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition);
+}
+
+QSymbianControl::QSymbianControl(QWidget *w)
+    : CCoeControl(), qwidget(w), m_ignoreFocusChanged(false)
+{
+}
+
+void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
+{
+    if (!desktop)
+    {
+        if (isWindowOwning or !qwidget->parentWidget())
+            CreateWindowL(S60->windowGroup());
+        else
+            /**
+             * TODO: in order to avoid creating windows for all ancestors of
+             * this widget up to the root window, the parameter passed to
+             * CreateWindowL should be
+             * qwidget->parentWidget()->effectiveWinId().  However, if we do
+             * this, then we need to take care of re-parenting when a window
+             * is created for a widget between this one and the root window.
+             */
+            CreateWindowL(qwidget->parentWidget()->winId());
+
+        // Necessary in order to be able to track the activation status of
+        // the control's window
+        qwidget->d_func()->createExtra();
+
+        SetFocusing(true);
+        m_longTapDetector = QLongTapTimer::NewL(this);
+    }
+}
+
+QSymbianControl::~QSymbianControl()
+{
+    if (S60->curWin == this)
+        S60->curWin = 0;
+    if (!QApplicationPrivate::is_app_closing)
+        setFocusSafely(false);
+    S60->appUi()->RemoveFromStack(this);
+    delete m_longTapDetector;
+}
+
+void QSymbianControl::setWidget(QWidget *w)
+{
+    qwidget = w;
+}
+void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation )
+{
+    QWidget *alienWidget;
+    QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY);
+    QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY);
+    alienWidget = qwidget->childAt(widgetPos);
+    if (!alienWidget)
+        alienWidget = qwidget;
+    QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~Qt::LeftButton);
+    QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | Qt::RightButton;
+    QMouseEvent mEvent(QEvent::MouseButtonPress, alienWidget->mapFrom(qwidget, widgetPos), globalPos,
+        Qt::RightButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier);
+
+    bool res = sendMouseEvent(alienWidget, &mEvent);
+
+#if !defined(QT_NO_CONTEXTMENU)
+    QContextMenuEvent contextMenuEvent(QContextMenuEvent::Mouse, widgetPos, globalPos, mEvent.modifiers());
+    qt_sendSpontaneousEvent(alienWidget, &contextMenuEvent);
+#endif
+
+    m_previousEventLongTap = true;
+}
+
+#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event)
+{
+    QApplicationPrivate *d = QApplicationPrivate::instance();
+
+    QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget);
+
+    while (d->appAllTouchPoints.count() <= event->PointerNumber())
+        d->appAllTouchPoints.append(QTouchEvent::TouchPoint(d->appAllTouchPoints.count()));
+
+    Qt::TouchPointStates allStates = 0;
+    for (int i = 0; i < d->appAllTouchPoints.count(); ++i) {
+        QTouchEvent::TouchPoint &touchPoint = d->appAllTouchPoints[i];
+
+        if (touchPoint.id() == event->PointerNumber()) {
+            Qt::TouchPointStates state;
+            switch (event->iType) {
+            case TPointerEvent::EButton1Down:
+            case TPointerEvent::EEnterHighPressure:
+                state = Qt::TouchPointPressed;
+                break;
+            case TPointerEvent::EButton1Up:
+            case TPointerEvent::EExitCloseProximity:
+                state = Qt::TouchPointReleased;
+                break;
+            case TPointerEvent::EDrag:
+                state = Qt::TouchPointMoved;
+                break;
+            default:
+                // how likely is this to happen?
+                state = Qt::TouchPointStationary;
+                break;
+            }
+            if (event->PointerNumber() == 0)
+                state |= Qt::TouchPointPrimary;
+            touchPoint.setState(state);
+
+            QPointF screenPos = QPointF(event->iPosition.iX, event->iPosition.iY);
+            touchPoint.setScreenPos(screenPos);
+            touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(),
+                                                screenPos.y() / screenGeometry.height()));
+
+            touchPoint.setPressure(event->Pressure() / qreal(d->maxTouchPressure));
+        } else if (touchPoint.state() != Qt::TouchPointReleased) {
+            // all other active touch points should be marked as stationary
+            touchPoint.setState(Qt::TouchPointStationary);
+        }
+
+        allStates |= touchPoint.state();
+    }
+
+    if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) {
+        // all touch points released
+        d->appAllTouchPoints.clear();
+    }
+
+    QApplicationPrivate::translateRawTouchEvent(qwidget,
+                                                QTouchEvent::TouchScreen,
+                                                d->appAllTouchPoints);
+}
+#endif
+
+void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent)
+{
+#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+    if (pEvent.IsAdvancedPointerEvent()) {
+        const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent();
+        translateAdvancedPointerEvent(advancedPointerEvent);
+        if (advancedPointerEvent->PointerNumber() != 0) {
+            // only send mouse events for the first touch point
+            return;
+        }
+    }
+#endif
+
+    m_longTapDetector->PointerEventL(pEvent);
+    QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent));
+}
+
+typedef QPair<QWidget*,QMouseEvent> Event;
+
+/*
+ * Helper function called by HandlePointerEvent - separated to keep that function readable
+ */
+static void generateEnterLeaveEvents(QList<Event> &events, QWidget *widgetUnderPointer,
+    QPoint globalPos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers)
+{
+    //moved to another widget, create enter and leave events
+    if (S60->lastPointerEventTarget) {
+        QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal(
+            S60->lastCursorPos), S60->lastCursorPos, button, QApplicationPrivate::mouse_buttons,
+            modifiers);
+        events.append(Event(S60->lastPointerEventTarget, mEventLeave));
+    }
+    if (widgetUnderPointer) {
+        QMouseEvent mEventEnter(QEvent::Enter, widgetUnderPointer->mapFromGlobal(globalPos),
+            globalPos, button, QApplicationPrivate::mouse_buttons, modifiers);
+
+        events.append(Event(widgetUnderPointer, mEventEnter));
+#ifndef QT_NO_CURSOR
+        S60->curWin = widgetUnderPointer->effectiveWinId();
+        if (!QApplication::overrideCursor()) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+            if (S60->brokenPointerCursors)
+                qt_symbian_set_pointer_sprite(widgetUnderPointer->cursor());
+            else
+#endif
+                qt_symbian_setWindowCursor(widgetUnderPointer->cursor(), S60->curWin);
+        }
+#endif
+    }
+}
+
+
+void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
+{
+    QMouseEvent::Type type;
+    Qt::MouseButton button;
+    mapS60MouseEventTypeToQt(&type, &button, &pEvent);
+    Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers);
+
+    if (m_previousEventLongTap)
+        if (type == QEvent::MouseButtonRelease){
+            button = Qt::RightButton;
+            QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & ~Qt::RightButton;
+            m_previousEventLongTap = false;
+        }
+    if (type == QMouseEvent::None)
+        return;
+
+    // store events for later sending/saving
+    QList<Event > events;
+
+    QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY);
+    TPoint controlScreenPos = PositionRelativeToScreen();
+    QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;
+
+    // widgets interested in the event
+    QWidget *widgetUnderPointer = qwidget->childAt(widgetPos);
+    if (!widgetUnderPointer)
+        widgetUnderPointer = qwidget; //i.e. this container widget
+
+    QWidget *widgetWithMouseGrab = QWidget::mouseGrabber();
+
+    // handle auto grab of pointer when pressing / releasing
+    if (!widgetWithMouseGrab && type == QEvent::MouseButtonPress) {
+        //if previously auto-grabbed, generate a fake mouse release (platform bug: mouse release event was lost)
+        if (S60->mousePressTarget) {
+            QMouseEvent mEvent(QEvent::MouseButtonRelease, S60->mousePressTarget->mapFromGlobal(globalPos), globalPos,
+                button, QApplicationPrivate::mouse_buttons, modifiers);
+            events.append(Event(S60->mousePressTarget,mEvent));
+        }
+        //auto grab the mouse
+        widgetWithMouseGrab = S60->mousePressTarget = widgetUnderPointer;
+        widgetWithMouseGrab->grabMouse();
+    }
+    if (widgetWithMouseGrab && widgetWithMouseGrab == S60->mousePressTarget && type == QEvent::MouseButtonRelease) {
+        //release the auto grab - note this release event still goes to the autograb widget
+        S60->mousePressTarget = 0;
+        widgetWithMouseGrab->releaseMouse();
+    }
+
+    QWidget *widgetToReceiveMouseEvent;
+    if (widgetWithMouseGrab)
+        widgetToReceiveMouseEvent = widgetWithMouseGrab;
+    else
+        widgetToReceiveMouseEvent = widgetUnderPointer;
+
+    //queue QEvent::Enter and QEvent::Leave, if the pointer has moved
+    if (widgetUnderPointer != S60->lastPointerEventTarget && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove))
+        generateEnterLeaveEvents(events, widgetUnderPointer, globalPos, button, modifiers);
+
+    //save global state
+    S60->lastCursorPos = globalPos;
+    S60->lastPointerEventPos = widgetPos;
+    S60->lastPointerEventTarget = widgetUnderPointer;
+
+#if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS)
+    if (S60->brokenPointerCursors)
+        qt_symbian_move_cursor_sprite();
+#endif
+
+    //queue this event.
+    Q_ASSERT(widgetToReceiveMouseEvent);
+    QMouseEvent mEvent(type, widgetToReceiveMouseEvent->mapFromGlobal(globalPos), globalPos,
+        button, QApplicationPrivate::mouse_buttons, modifiers);
+    events.append(Event(widgetToReceiveMouseEvent,mEvent));
+    QEventDispatcherS60 *dispatcher;
+    // It is theoretically possible for someone to install a different event dispatcher.
+    if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widgetToReceiveMouseEvent->d_func()->threadData->eventDispatcher)) != 0) {
+        if (dispatcher->excludeUserInputEvents()) {
+            for (int i=0;i < events.count();++i)
+            {
+                Event next = events[i];
+                dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second));
+            }
+            return;
+        }
+    }
+
+    //send events in the queue
+    for (int i=0;i < events.count();++i)
+    {
+        Event next = events[i];
+        sendMouseEvent(next.first, &(next.second));
+    }
+}
+
+bool QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent)
+{
+    return qt_sendSpontaneousEvent(widget, mEvent);
+}
+
+TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type)
+{
+    TKeyResponse r = EKeyWasNotConsumed;
+    QT_TRYCATCH_LEAVING(r = OfferKeyEvent(keyEvent, type));
+    return r;
+}
+
+TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type)
+{
+    switch (type) {
+    //case EEventKeyDown: // <-- Intentionally left out. See below.
+    case EEventKeyUp:
+    case EEventKey:
+    {
+        // S60 has a confusing way of delivering key events. There are three types of
+        // events: EKeyEvent, EKeyEventDown and EKeyEventUp. When a key is pressed, the
+        // two first events are generated. When releasing the key, the last one is
+        // generated.
+        // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp events,
+        // we need to do some special tricks to map it to the Qt way. First, we completely
+        // discard EKeyEventDown events, since they are redundant. Second, since
+        // EKeyEventUp does not give us a keysym, we need to cache the keysyms from
+        // the EKeyEvent events. This is what resolveS60ScanCode does.
+
+
+        // ### hackish way to send Qt application to background when pressing right softkey
+        /*
+        if( keyEvent.iScanCode == EStdKeyDevice1 ) {
+            S60->window_group->SetOrdinalPosition(-1);
+            qApp->setActiveWindow(0);
+            return EKeyWasNotConsumed;
+        }
+        */
+
+        TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode,
+                keyEvent.iCode);
+        int keyCode;
+        if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) {
+            // Normal characters keys.
+            keyCode = s60Keysym;
+        } else {
+            // Special S60 keys.
+            keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym);
+        }
+
+#ifndef QT_NO_CURSOR
+        if (S60->mouseInteractionEnabled && S60->virtualMouseRequired) {
+            //translate keys to pointer
+            if (keyCode >= Qt::Key_Left && keyCode <= Qt::Key_Down || keyCode == Qt::Key_Select) {
+                /*Explanation about virtualMouseAccel:
+                 Tapping an arrow key allows precise pixel positioning
+                 Holding an arrow key down, acceleration is applied to allow cursor
+                 to be quickly moved to another part of the screen by key repeats.
+                 */
+                if (S60->virtualMouseLastKey == keyCode) {
+                    S60->virtualMouseAccel *= 2;
+                    if (S60->virtualMouseAccel > S60->virtualMouseMaxAccel)
+                        S60->virtualMouseAccel = S60->virtualMouseMaxAccel;
+                }
+                else
+                    S60->virtualMouseAccel = 1;
+                S60->virtualMouseLastKey = keyCode;
+
+                QPoint pos = QCursor::pos();
+                TPointerEvent fakeEvent;
+                TInt x = pos.x();
+                TInt y = pos.y();
+                if (type == EEventKeyUp) {
+                    if (keyCode == Qt::Key_Select)
+                        fakeEvent.iType = TPointerEvent::EButton1Up;
+                    S60->virtualMouseAccel = 1;
+                    S60->virtualMouseLastKey = 0;
+                }
+                else if (type == EEventKey) {
+                    switch (keyCode) {
+                    case Qt::Key_Left:
+                        x -= S60->virtualMouseAccel;
+                        fakeEvent.iType = TPointerEvent::EMove;
+                        break;
+                    case Qt::Key_Right:
+                        x += S60->virtualMouseAccel;
+                        fakeEvent.iType = TPointerEvent::EMove;
+                        break;
+                    case Qt::Key_Up:
+                        y -= S60->virtualMouseAccel;
+                        fakeEvent.iType = TPointerEvent::EMove;
+                        break;
+                    case Qt::Key_Down:
+                        y += S60->virtualMouseAccel;
+                        fakeEvent.iType = TPointerEvent::EMove;
+                        break;
+                    case Qt::Key_Select:
+                        fakeEvent.iType = TPointerEvent::EButton1Down;
+                        break;
+                    }
+                }
+                //clip to screen size (window server allows a sprite hotspot to be outside the screen)
+                if (x < 0)
+                    x = 0;
+                else if (x >= S60->screenWidthInPixels)
+                    x = S60->screenWidthInPixels - 1;
+                if (y < 0)
+                    y = 0;
+                else if (y >= S60->screenHeightInPixels)
+                    y = S60->screenHeightInPixels - 1;
+                TPoint epos(x, y);
+                TPoint cpos = epos - PositionRelativeToScreen();
+                fakeEvent.iModifiers = keyEvent.iModifiers;
+                fakeEvent.iPosition = cpos;
+                fakeEvent.iParentPosition = epos;
+                HandlePointerEvent(fakeEvent);
+                return EKeyWasConsumed;
+            }
+            else {
+                S60->virtualMouseLastKey = keyCode;
+                S60->virtualMouseAccel = 1;
+            }
+        }
+#endif
+
+        Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers);
+        QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode,
+                mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods),
+                false, 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers);
+//        WId wid = reinterpret_cast<RWindowGroup *>(keyEvent.Handle())->Child();
+//        if (!wid)
+//             Could happen if window isn't shown yet.
+//            return EKeyWasNotConsumed;
+        QWidget *widget;
+        widget = QWidget::keyboardGrabber();
+        if (!widget) {
+            if (QApplicationPrivate::popupWidgets != 0) {
+                widget = QApplication::activePopupWidget()->focusWidget();
+                if (!widget) {
+                    widget = QApplication::activePopupWidget();
+                }
+            } else {
+                widget = QApplicationPrivate::focus_widget;
+                if (!widget) {
+                    widget = qwidget;
+                }
+            }
+        }
+
+        QEventDispatcherS60 *dispatcher;
+        // It is theoretically possible for someone to install a different event dispatcher.
+        if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) != 0) {
+            if (dispatcher->excludeUserInputEvents()) {
+                dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent));
+                return EKeyWasConsumed;
+            }
+        }
+        return sendKeyEvent(widget, &qKeyEvent);
+    }
+    }
+    return EKeyWasNotConsumed;
+}
+
+void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent)
+{
+    switch (inputEvent->type()) {
+    case QEvent::KeyPress:
+    case QEvent::KeyRelease:
+        sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent));
+        break;
+    case QEvent::MouseButtonDblClick:
+    case QEvent::MouseButtonPress:
+    case QEvent::MouseButtonRelease:
+    case QEvent::MouseMove:
+        sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent));
+        break;
+    default:
+        // Shouldn't get here.
+        Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown");
+        break;
+    }
+}
+
+TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent)
+{
+#if !defined(QT_NO_IM) && defined(Q_WS_S60)
+    if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) {
+        QInputContext *qic = widget->inputContext();
+        if (qic && qic->filterEvent(keyEvent))
+            return EKeyWasConsumed;
+    }
+#endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
+
+    if (widget && qt_sendSpontaneousEvent(widget, keyEvent))
+        if (keyEvent->isAccepted())
+            return EKeyWasConsumed;
+
+    return EKeyWasNotConsumed;
+}
+
+#if !defined(QT_NO_IM) && defined(Q_WS_S60)
+TCoeInputCapabilities QSymbianControl::InputCapabilities() const
+{
+    QWidget *w = 0;
+
+    if (qwidget->hasFocus())
+        w = qwidget;
+    else
+        w = qwidget->focusWidget();
+
+    QCoeFepInputContext *ic;
+    if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled)
+            && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) {
+        return ic->inputCapabilities();
+    } else {
+        return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0);
+    }
+}
+#endif
+
+void QSymbianControl::Draw(const TRect& controlRect) const
+{
+    QWindowSurface *surface = qwidget->windowSurface();
+    QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL;
+
+    if (!engine)
+        return;
+
+    // Map source rectangle into coordinates of the backing store.
+    const QPoint controlBase(controlRect.iTl.iX, controlRect.iTl.iY);
+    const QPoint backingStoreBase = qwidget->mapTo(qwidget->window(), controlBase);
+    const TRect backingStoreRect(TPoint(backingStoreBase.x(), backingStoreBase.y()), controlRect.Size());
+
+    if (engine->type() == QPaintEngine::Raster) {
+        QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface());
+        CFbsBitmap *bitmap = s60Surface->symbianBitmap();
+        CWindowGc &gc = SystemGc();
+
+        if(!qwidget->d_func()->extraData()->disableBlit) {
+            if (qwidget->d_func()->isOpaque)
+                gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+            gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect);
+	    }
+    } else {
+        surface->flush(qwidget, QRegion(qt_TRect2QRect(backingStoreRect)), QPoint());
+    }
+}
+
+void QSymbianControl::SizeChanged()
+{
+    CCoeControl::SizeChanged();
+
+    QSize oldSize = qwidget->size();
+    QSize newSize(Size().iWidth, Size().iHeight);
+
+    if (oldSize != newSize) {
+        QRect cr = qwidget->geometry();
+        cr.setSize(newSize);
+        qwidget->data->crect = cr;
+        if (qwidget->isVisible()) {
+            QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData();
+            bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
+            if (!slowResize && tlwExtra)
+                tlwExtra->inTopLevelResize = true;
+            QResizeEvent e(newSize, oldSize);
+            qt_sendSpontaneousEvent(qwidget, &e);
+            if (!qwidget->testAttribute(Qt::WA_StaticContents))
+                qwidget->d_func()->syncBackingStore();
+            if (!slowResize && tlwExtra)
+                tlwExtra->inTopLevelResize = false;
+        }
+    }
+}
+
+void QSymbianControl::PositionChanged()
+{
+    CCoeControl::PositionChanged();
+
+    QPoint oldPos = qwidget->geometry().topLeft();
+    QPoint newPos(Position().iX, Position().iY);
+
+    if (oldPos != newPos) {
+        QRect cr = qwidget->geometry();
+        cr.moveTopLeft(newPos);
+        qwidget->data->crect = cr;
+        QTLWExtra *top = qwidget->d_func()->maybeTopData();
+        if (top)
+            top->normalGeometry = cr;
+        if (qwidget->isVisible()) {
+            QMoveEvent e(newPos, oldPos);
+            qt_sendSpontaneousEvent(qwidget, &e);
+        } else {
+            QMoveEvent * e = new QMoveEvent(newPos, oldPos);
+            QApplication::postEvent(qwidget, e);
+        }
+    }
+}
+
+void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
+{
+    if (m_ignoreFocusChanged)
+        return;
+
+    // Popups never get focused, but still receive the FocusChanged when they are hidden.
+    if (QApplicationPrivate::popupWidgets != 0
+            || (qwidget->windowType() & Qt::Popup) == Qt::Popup)
+        return;
+
+    if (IsFocused() && IsVisible()) {
+        QApplication::setActiveWindow(qwidget->window());
+#ifdef Q_WS_S60
+        // If widget is fullscreen, hide status pane and button container
+        // otherwise show them.
+        CEikStatusPane* statusPane = S60->statusPane();
+        CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer();
+        bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
+        if (statusPane && (statusPane->IsVisible() == isFullscreen))
+            statusPane->MakeVisible(!isFullscreen);
+        if (buttonGroup && (buttonGroup->IsVisible() == isFullscreen))
+            buttonGroup->MakeVisible(!isFullscreen);
+#endif
+    } else if (QApplication::activeWindow() == qwidget->window()) {
+        QApplication::setActiveWindow(0);
+    }
+    // else { We don't touch the active window unless we were explicitly activated or deactivated }
+}
+
+void QSymbianControl::HandleResourceChange(int resourceType)
+{
+    switch (resourceType) {
+    case KInternalStatusPaneChange:
+        qwidget->d_func()->setWindowIcon_sys(true);
+        break;
+    case KUidValueCoeFontChangeEvent:
+        // font change event
+        break;
+#ifdef Q_WS_S60
+    case KEikDynamicLayoutVariantSwitch:
+    {
+        if (qwidget->isFullScreen()) {
+            SetExtentToWholeScreen();
+        } else if (qwidget->isMaximized()) {
+            TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
+            SetExtent(r.iTl, r.Size());
+        }
+        break;
+    }
+#endif
+    default:
+        break;
+    }
+
+    CCoeControl::HandleResourceChange(resourceType);
+
+}
+void QSymbianControl::CancelLongTapTimer()
+{
+    m_longTapDetector->Cancel();
+}
+
+TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id)
+{
+    if (id.iUid == ETypeId)
+        return id.MakePtr(this);
+
+    return CCoeControl::MopSupplyObject(id);
+}
+
+void QSymbianControl::setFocusSafely(bool focus)
+{
+    // The stack hack in here is very unfortunate, but it is the only way to ensure proper
+    // focus in Symbian. If this is not executed, the control which happens to be on
+    // the top of the stack may randomly be assigned focus by Symbian, for example
+    // when creating new windows (specifically in CCoeAppUi::HandleStackChanged()).
+    if (focus) {
+        S60->appUi()->RemoveFromStack(this);
+        // Symbian doesn't automatically remove focus from the last focused control, so we need to
+        // remember it and clear focus ourselves.
+        if (lastFocusedControl && lastFocusedControl != this)
+            lastFocusedControl->SetFocus(false);
+        QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
+                ECoeStackPriorityDefault + 1, ECoeStackFlagStandard)); // Note the + 1
+        lastFocusedControl = this;
+        this->SetFocus(true);
+    } else {
+        S60->appUi()->RemoveFromStack(this);
+        QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
+                ECoeStackPriorityDefault, ECoeStackFlagStandard));
+        if(this == lastFocusedControl)
+            lastFocusedControl = 0;
+        this->SetFocus(false);
+    }
+}
+
+/*!
+    \typedef QApplication::QS60MainApplicationFactory
+    \since 4.6
+
+    This is a typedef for a pointer to a function with the following
+    signature:
+
+    \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 47
+
+    \sa QApplication::QApplication()
+*/
+
+/*!
+    \since 4.6
+
+    Creates an application using the application factory given in
+    \a factory, and using \a argc command line arguments in \a argv.
+    \a factory can be leaving, but the error will be converted to a
+    standard exception.
+
+    This function is only available on S60.
+*/
+QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv)
+    : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
+{
+    Q_D(QApplication);
+    S60->s60ApplicationFactory = factory;
+    d->construct();
+}
+
+QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int _internal)
+    : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
+{
+    Q_D(QApplication);
+    S60->s60ApplicationFactory = factory;
+    d->construct();
+    QApplicationPrivate::app_compile_version = _internal;
+}
+
+void qt_init(QApplicationPrivate * /* priv */, int)
+{
+    if (!CCoeEnv::Static()) {
+        // The S60 framework creates a new trap handler which will render any existing traps
+        // invalid as long as it is active. This means that all code in main() that occurs after
+        // the QApplication construction needs to be surrounded by a new trap, despite having
+        // an outer one already. To avoid this, we save the original trap handler here, and set
+        // it back after the S60 framework is constructed. Then we restore it right before the S60
+        // framework destruction.
+        TTrapHandler *origTrapHandler = User::TrapHandler();
+
+        // The S60 framework has not been initalized. We need to do it.
+        TApaApplicationFactory factory(S60->s60ApplicationFactory ?
+                S60->s60ApplicationFactory : newS60Application);
+        CApaCommandLine* commandLine = 0;
+        TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
+        // After this construction, CEikonEnv will be available from CEikonEnv::Static().
+        // (much like our qApp).
+        CEikonEnv* coe = new CEikonEnv;
+        QT_TRAP_THROWING(coe->ConstructAppFromCommandLineL(factory,*commandLine));
+        delete commandLine;
+
+        S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler);
+
+        S60->qtOwnsS60Environment = true;
+    } else {
+        S60->qtOwnsS60Environment = false;
+    }
+
+#ifdef QT_NO_DEBUG
+    if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty())
+#endif
+        S60->wsSession().SetAutoFlush(ETrue);
+
+    S60->updateScreenSize();
+
+
+    TDisplayMode mode = S60->screenDevice()->DisplayMode();
+    S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode);
+
+    //NB: RWsSession::GetColorModeList tells you what window modes are supported,
+    //not what bitmap formats.
+    if(QSysInfo::symbianVersion() == QSysInfo::SV_9_2)
+        S60->supportsPremultipliedAlpha = 0;
+    else
+        S60->supportsPremultipliedAlpha = 1;
+
+    RProcess me;
+    TSecureId securId = me.SecureId();
+    S60->uid = securId.operator TUid();
+
+    // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app,
+    // and for dimming behind modal windows
+	S60->windowGroup().EnableFocusChangeEvents();
+
+	//Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this)
+    const TInt KMachineUidSamsungI8510 = 0x2000C51E;
+    // HAL::Get(HALData::EPen, TInt& result) may set 'result' to 1 on some 3.1 systems (e.g. N95).
+    // But we know that S60 systems below 5.0 did not support touch.
+    static const bool touchIsUnsupportedOnSystem =
+        QSysInfo::s60Version() == QSysInfo::SV_S60_3_1
+        || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2;
+    TInt machineUID;
+    TInt mouse;
+    TInt touch;
+    TInt err;
+    err = HAL::Get(HALData::EMouse, mouse);
+    if (err != KErrNone)
+        mouse = 0;
+    err = HAL::Get(HALData::EMachineUid, machineUID);
+    if (err != KErrNone)
+        machineUID = 0;
+    err = HAL::Get(HALData::EPen, touch);
+    if (err != KErrNone || touchIsUnsupportedOnSystem)
+        touch = 0;
+#ifdef __WINS__
+    if(QSysInfo::symbianVersion() <= QSysInfo::SV_9_4) {
+        //for symbian SDK emulator, force values to match typical devices.
+        mouse = 0;
+        touch = touchIsUnsupportedOnSystem ? 0 : 1;
+    }
+#endif
+    if (mouse || machineUID == KMachineUidSamsungI8510) {
+        S60->hasTouchscreen = false;
+        S60->virtualMouseRequired = false;
+    }
+    else if (!touch) {
+        S60->hasTouchscreen = false;
+        S60->virtualMouseRequired = true;
+    }
+    else {
+        S60->hasTouchscreen = true;
+        S60->virtualMouseRequired = false;
+    }
+
+    if (touch) {
+        QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
+    } else {
+        QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional;
+    }
+
+#ifndef QT_NO_CURSOR
+    //Check if window server pointer cursors are supported or not
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+    //In generic binary, use the HAL and OS version
+    //Any other known good phones should be added here.
+    if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4
+        && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion()
+        != QSysInfo::SV_9_2)) {
+        S60->brokenPointerCursors = false;
+        qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
+    }
+    else
+        S60->brokenPointerCursors = true;
+#endif
+
+    if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+        if (S60->brokenPointerCursors) {
+            qt_symbian_set_pointer_sprite(Qt::ArrowCursor);
+            qt_symbian_show_pointer_sprite();
+        }
+        else
+#endif
+            S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
+    }
+#endif
+
+    QFont systemFont;
+    systemFont.setFamily(systemFont.defaultFamily());
+    QApplicationPrivate::setSystemFont(systemFont);
+
+/*
+ ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
+    int argc = priv->argc;
+    char **argv = priv->argv;
+
+    // Get command line params
+    int j = argc ? 1 : 0;
+    for (int i=1; i<argc; i++) {
+        if (argv[i] && *argv[i] != '-') {
+            argv[j++] = argv[i];
+            continue;
+        }
+
+#if defined(QT_DEBUG)
+        if (qstrcmp(argv[i], "-nograb") == 0)
+            appNoGrab = !appNoGrab;
+        else
+#endif // QT_DEBUG
+            ;
+    }
+*/
+
+    // Register WId with the metatype system.  This is to enable
+    // QWidgetPrivate::create_sys to used delayed slot invokation in order
+    // to destroy WId objects during reparenting.
+    qRegisterMetaType<WId>("WId");
+}
+
+/*****************************************************************************
+  qt_cleanup() - cleans up when the application is finished
+ *****************************************************************************/
+void qt_cleanup()
+{
+    QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles
+// S60 structure and window server session are freed in eventdispatcher destructor as they are needed there
+
+    // It's important that this happens here, before the event dispatcher gets
+    // deleted, because the input context needs the event loop one last time before
+    // it dies.
+    delete QApplicationPrivate::inputContext;
+    QApplicationPrivate::inputContext = 0;
+
+    //Change mouse pointer back
+    S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
+
+    if (S60->qtOwnsS60Environment) {
+        // Restore the S60 framework trap handler. See qt_init().
+        User::SetTrapHandler(S60->s60InstalledTrapHandler);
+
+        CEikonEnv* coe = CEikonEnv::Static();
+        coe->PrepareToExit();
+        // The CEikonEnv itself is destroyed in here.
+        coe->DestroyEnvironment();
+    }
+}
+
+void QApplicationPrivate::initializeWidgetPaletteHash()
+{
+    // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash()
+    // Possibly a task fot the S60Style guys
+}
+
+void QApplicationPrivate::createEventDispatcher()
+{
+    Q_Q(QApplication);
+    eventDispatcher = new QEventDispatcherS60(q);
+}
+
+QString QApplicationPrivate::appName() const
+{
+    return QCoreApplicationPrivate::appName();
+}
+
+bool QApplicationPrivate::modalState()
+{
+    return app_do_modal;
+}
+
+void QApplicationPrivate::enterModal_sys(QWidget *widget)
+{
+    if (widget) {
+        widget->effectiveWinId()->DrawableWindow()->FadeBehind(ETrue);
+        // Modal partial screen dialogs (like queries) capture pointer events.
+        // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
+        widget->effectiveWinId()->SetGloballyCapturing(ETrue);
+        widget->effectiveWinId()->SetPointerCapture(ETrue);
+    }
+    if (!qt_modal_stack)
+        qt_modal_stack = new QWidgetList;
+    qt_modal_stack->insert(0, widget);
+    app_do_modal = true;
+}
+
+void QApplicationPrivate::leaveModal_sys(QWidget *widget)
+{
+    if (widget) {
+        widget->effectiveWinId()->DrawableWindow()->FadeBehind(EFalse);
+        // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
+        widget->effectiveWinId()->SetGloballyCapturing(EFalse);
+        widget->effectiveWinId()->SetPointerCapture(EFalse);
+    }
+    if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
+        if (qt_modal_stack->isEmpty()) {
+            delete qt_modal_stack;
+            qt_modal_stack = 0;
+        }
+    }
+    app_do_modal = qt_modal_stack != 0;
+}
+
+void QApplicationPrivate::openPopup(QWidget *popup)
+{
+    if (!QApplicationPrivate::popupWidgets)
+        QApplicationPrivate::popupWidgets = new QWidgetList;
+    QApplicationPrivate::popupWidgets->append(popup);
+
+
+    // Cancel focus widget pointer capture and long tap timer
+    if (QApplication::focusWidget()) {
+        static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer();
+        QApplication::focusWidget()->effectiveWinId()->SetPointerCapture(false);
+        }
+
+    if (!qt_nograb()) {
+        // Cancel pointer capture and long tap timer for earlier popup
+        int popupCount = QApplicationPrivate::popupWidgets->count();
+        if (popupCount > 1) {
+            QWidget* prevPopup = QApplicationPrivate::popupWidgets->at(popupCount-2);
+            static_cast<QSymbianControl*>(prevPopup->effectiveWinId())->CancelLongTapTimer();
+            prevPopup->effectiveWinId()->SetPointerCapture(false);
+        }
+
+        // Enable pointer capture for this (topmost) popup
+        Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
+        WId id = popup->effectiveWinId();
+        id->SetPointerCapture(true);
+    }
+
+    // popups are not focus-handled by the window system (the first
+    // popup grabbed the keyboard), so we have to do that manually: A
+    // new popup gets the focus
+    QWidget *fw = popup->focusWidget();
+    if (fw) {
+        fw->setFocus(Qt::PopupFocusReason);
+    } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
+        fw = QApplication::focusWidget();
+        if (fw) {
+            QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
+            q_func()->sendEvent(fw, &e);
+        }
+    }
+}
+
+void QApplicationPrivate::closePopup(QWidget *popup)
+{
+    if (!QApplicationPrivate::popupWidgets)
+        return;
+    QApplicationPrivate::popupWidgets->removeAll(popup);
+
+    // Cancel pointer capture and long tap for this popup
+    WId id = popup->effectiveWinId();
+    id->SetPointerCapture(false);
+    static_cast<QSymbianControl*>(id)->CancelLongTapTimer();
+
+    if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
+        delete QApplicationPrivate::popupWidgets;
+        QApplicationPrivate::popupWidgets = 0;
+        if (!qt_nograb()) {                        // grabbing not disabled
+            Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
+            if (QWidgetPrivate::mouseGrabber != 0)
+                QWidgetPrivate::mouseGrabber->grabMouse();
+
+            if (QWidgetPrivate::keyboardGrabber != 0)
+                QWidgetPrivate::keyboardGrabber->grabKeyboard();
+
+        QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
+              : q_func()->focusWidget();
+          if (fw) {
+              if (fw != q_func()->focusWidget()) {
+                  fw->setFocus(Qt::PopupFocusReason);
+              } else {
+                  QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
+                  q_func()->sendEvent(fw, &e);
+              }
+          }
+        }
+    } else {
+
+        // popups are not focus-handled by the window system (the
+        // first popup grabbed the keyboard), so we have to do that
+        // manually: A popup was closed, so the previous popup gets
+        // the focus.
+        QWidget* aw = QApplicationPrivate::popupWidgets->last();
+        if (QWidget *fw = QApplication::focusWidget()) {
+            QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
+            q_func()->sendEvent(fw, &e);
+        }
+
+        // Enable pointer capture for previous popup
+        if (aw) {
+            aw->effectiveWinId()->SetPointerCapture(true);
+        }
+    }
+}
+
+QWidget * QApplication::topLevelAt(QPoint const& point)
+{
+    QWidget *found = 0;
+    int lowestZ = INT_MAX;
+    QWidgetList list = QApplication::topLevelWidgets();
+    for (int i = 0; i < list.count(); ++i) {
+        QWidget *widget = list.at(i);
+        if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
+            Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+            if (widget->geometry().adjusted(0,0,1,1).contains(point)) {
+                // At this point we know there is a Qt widget under the point.
+                // Now we need to make sure it is the top most in the z-order.
+                RDrawableWindow *const window = widget->effectiveWinId()->DrawableWindow();
+                int z = window->OrdinalPosition();
+                if (z < lowestZ) {
+                    lowestZ = z;
+                    found = widget;
+                }
+            }
+        }
+    }
+    return found;
+}
+
+void QApplication::alert(QWidget * /* widget */, int /* duration */)
+{
+    // TODO: Implement QApplication::alert(QWidget *widget, int duration)
+}
+
+int QApplication::doubleClickInterval()
+{
+    TTimeIntervalMicroSeconds32 us;
+    TInt distance;
+    S60->wsSession().GetDoubleClickSettings(us, distance);
+    return (us.Int() / 1000);
+}
+
+void QApplication::setDoubleClickInterval(int ms)
+{
+    TTimeIntervalMicroSeconds32 newUs( ms * 1000);
+    TTimeIntervalMicroSeconds32 us;
+    TInt distance;
+    S60->wsSession().GetDoubleClickSettings(us, distance);
+    if (us != newUs)
+        S60->wsSession().SetDoubleClick(newUs, distance);
+}
+
+int QApplication::keyboardInputInterval()
+{
+    return QApplicationPrivate::keyboard_input_time;
+}
+
+void QApplication::setKeyboardInputInterval(int ms)
+{
+    QApplicationPrivate::keyboard_input_time = ms;
+}
+
+int QApplication::cursorFlashTime()
+{
+    return QApplicationPrivate::cursor_flash_time;
+}
+
+void QApplication::setCursorFlashTime(int msecs)
+{
+    QApplicationPrivate::cursor_flash_time = msecs;
+}
+
+void QApplication::beep()
+{
+    TInt frequency=440;
+    TTimeIntervalMicroSeconds duration(500000);
+    QS60Beep* beep=NULL;
+    TRAPD(err, beep=QS60Beep::NewL(frequency, duration));
+    if (!err)
+        beep->Play();
+    delete beep;
+    beep=NULL;
+}
+
+/*!
+    \warning This function is only available on Symbian.
+    \since 4.6
+
+    This function processes an individual Symbian event
+    \a event. It returns 1 if the event was handled, 0 if
+    the \a event was not handled, and -1 if the event was
+    not handled because the event is not known to Qt.
+ */
+
+int QApplication::symbianProcessEvent(const QSymbianEvent *event)
+{
+    Q_D(QApplication);
+
+    QScopedLoopLevelCounter counter(d->threadData);
+
+    QWidget *w = qApp ? qApp->focusWidget() : 0;
+    if (w) {
+        QInputContext *ic = w->inputContext();
+        if (ic && ic->symbianFilterEvent(w, event))
+            return 1;
+    }
+
+    if (symbianEventFilter(event))
+        return 1;
+
+    switch (event->type()) {
+    case QSymbianEvent::WindowServerEvent:
+        return d->symbianProcessWsEvent(event->windowServerEvent());
+    case QSymbianEvent::CommandEvent:
+        return d->symbianHandleCommand(event->command());
+    case QSymbianEvent::ResourceChangeEvent:
+        return d->symbianResourceChange(event->resourceChangeType());
+    default:
+        return -1;
+    }
+}
+
+int QApplicationPrivate::symbianProcessWsEvent(const TWsEvent *event)
+{
+    // Qt event handling. Handle some events regardless of if the handle is in our
+    // widget map or not.
+    CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle());
+    const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control);
+    switch (event->Type()) {
+    case EEventPointerEnter:
+        if (controlInMap)
+            return 1; // Qt::Enter will be generated in HandlePointerL
+        break;
+    case EEventPointerExit:
+        if (controlInMap) {
+            if (S60) {
+                // mouseEvent outside our window, send leave event to last focused widget
+                QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos,
+                    Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier);
+                if (S60->lastPointerEventTarget)
+                    qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent);
+                S60->lastPointerEventTarget = 0;
+            }
+            return 1;
+        }
+        break;
+    case EEventScreenDeviceChanged:
+        if (S60)
+            S60->updateScreenSize();
+        if (qt_desktopWidget) {
+            QSize oldSize = qt_desktopWidget->size();
+            qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels);
+            qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels);
+            QResizeEvent e(qt_desktopWidget->size(), oldSize);
+            QApplication::sendEvent(qt_desktopWidget, &e);
+        }
+        return 0; // Propagate to CONE
+    case EEventWindowVisibilityChanged:
+        if (controlInMap) {
+            const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
+            QWidget *w = QWidgetPrivate::mapper->value(control);
+            if (!w->d_func()->maybeTopData())
+                break;
+            if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) {
+                delete w->d_func()->topData()->backingStore;
+                w->d_func()->topData()->backingStore = 0;
+                // :QTP:QT-2506:remove this when QT-2506 is fixed
+                if (S60)
+                    S60->wsSession().Flush();
+            } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
+                       && !w->d_func()->maybeBackingStore()) {
+                w->d_func()->topData()->backingStore = new QWidgetBackingStore(w);
+                w->d_func()->invalidateBuffer(w->rect());
+                w->repaint();
+            }
+            return 1;
+        }
+        break;
+    case EEventFocusGained:
+#ifndef QT_NO_CURSOR
+        //re-enable mouse interaction
+        if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+            if (S60->brokenPointerCursors)
+                qt_symbian_show_pointer_sprite();
+            else
+#endif
+                S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
+        }
+#endif
+        break;
+    case EEventFocusLost:
+#ifndef QT_NO_CURSOR
+        //disable mouse as may be moving to application that does not support it
+        if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+            if (S60->brokenPointerCursors)
+                qt_symbian_hide_pointer_sprite();
+            else
+#endif
+                S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
+        }
+#endif
+        break;
+	default:
+        break;
+    }
+
+    if (!controlInMap)
+        return -1;
+
+    return 0;
+}
+
+/*!
+  \warning This virtual function is only available on Symbian.
+  \since 4.6
+
+  If you create an application that inherits QApplication and reimplement
+  this function, you get direct access to events that the are received
+  from Symbian. The events are passed in the \a event parameter.
+
+  Return true if you want to stop the event from being processed. Return
+  false for normal event dispatching. The default implementation returns
+  false, and does nothing with \a event.
+ */
+bool QApplication::symbianEventFilter(const QSymbianEvent *event)
+{
+    Q_UNUSED(event);
+    return false;
+}
+
+/*!
+  \warning This function is only available on Symbian.
+  \since 4.6
+
+  Handles \a{command}s which are typically handled by
+  CAknAppUi::HandleCommandL(). Qts Ui integration into Symbian is
+  partially achieved by deriving from CAknAppUi. Currently, exit,
+  menu and softkey commands are handled.
+
+  \sa s60EventFilter(), s60ProcessEvent()
+*/
+int QApplicationPrivate::symbianHandleCommand(int command)
+{
+    Q_Q(QApplication);
+    int ret = 0;
+
+    switch (command) {
+#ifdef Q_WS_S60
+    case EAknSoftkeyExit: {
+        QCloseEvent ev;
+        QApplication::sendSpontaneousEvent(q, &ev);
+        if (ev.isAccepted()) {
+            q->quit();
+            ret = 1;
+        }
+        break;
+    }
+#endif
+    case EEikCmdExit:
+        q->quit();
+        ret = 1;
+        break;
+    default:
+        bool handled = QSoftKeyManager::handleCommand(command);
+        if (handled)
+            ret = 1;
+#ifdef Q_WS_S60
+        else
+            ret = QMenuBarPrivate::symbianCommands(command);
+#endif
+        break;
+    }
+
+    return ret;
+}
+
+/*!
+  \warning This function is only available on Symbian.
+  \since 4.6
+
+  Handles the resource change specified by \a type.
+
+  Currently, KEikDynamicLayoutVariantSwitch and
+  KAknsMessageSkinChange are handled.
+ */
+int QApplicationPrivate::symbianResourceChange(int type)
+{
+    int ret = 0;
+
+    switch (type) {
+#ifdef Q_WS_S60
+    case KEikDynamicLayoutVariantSwitch:
+        {
+        if (S60)
+            S60->updateScreenSize();
+
+#ifndef QT_NO_STYLE_S60
+        QS60Style *s60Style = 0;
+
+#ifndef QT_NO_STYLE_STYLESHEET
+        QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style());
+        if (proxy)
+            s60Style = qobject_cast<QS60Style*>(proxy->baseStyle());
+        else
+#endif
+            s60Style = qobject_cast<QS60Style*>(QApplication::style());
+
+        if (s60Style) {
+            s60Style->d_func()->handleDynamicLayoutVariantSwitch();
+            ret = 1;
+        }
+#endif
+        }
+        break;
+
+#ifndef QT_NO_STYLE_S60
+    case KAknsMessageSkinChange:
+        if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) {
+            s60Style->d_func()->handleSkinChange();
+            ret = 1;
+        }
+        break;
+#endif
+#endif // Q_WS_S60
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+#ifndef QT_NO_WHEELEVENT
+int QApplication::wheelScrollLines()
+{
+    return QApplicationPrivate::wheel_scroll_lines;
+}
+
+void QApplication::setWheelScrollLines(int n)
+{
+    QApplicationPrivate::wheel_scroll_lines = n;
+}
+#endif //QT_NO_WHEELEVENT
+
+bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */)
+{
+    // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect)
+    return false;
+}
+
+void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */)
+{
+    // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
+}
+
+TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym)
+{
+    if (keysym) {
+        // If keysym is specified, cache it.
+        scanCodeCache.insert(scanCode, keysym);
+        return keysym;
+    } else {
+        // If not, retrieve the cached version.
+        return scanCodeCache[scanCode];
+    }
+}
+
+void QApplicationPrivate::initializeMultitouch_sys()
+{
+#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+    if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone)
+        maxTouchPressure = KMaxTInt;
+#endif
+}
+
+void QApplicationPrivate::cleanupMultitouch_sys()
+{ }
+
+#ifndef QT_NO_SESSIONMANAGER
+QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */)
+{
+
+}
+
+QSessionManager::~QSessionManager()
+{
+
+}
+
+bool QSessionManager::allowsInteraction()
+{
+    return false;
+}
+
+void QSessionManager::cancel()
+{
+
+}
+#endif //QT_NO_SESSIONMANAGER
+
+#ifdef QT_KEYPAD_NAVIGATION
+/*
+ * Show/Hide the mouse cursor depending on phone type and chosen mode
+ */
+void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode)
+{
+#ifndef QT_NO_CURSOR
+    const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto
+        && !S60->hasTouchscreen)
+        || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible;
+    const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto
+        && !S60->hasTouchscreen)
+        || mode == Qt::NavigationModeCursorForceVisible;
+
+    if (!wasCursorOn && isCursorOn) {
+        //Show the cursor, when changing from another mode to cursor mode
+        qt_symbian_set_cursor_visible(true);
+    }
+    else if (wasCursorOn && !isCursorOn) {
+        //Hide the cursor, when leaving cursor mode
+        qt_symbian_set_cursor_visible(false);
+    }
+#endif
+    QApplicationPrivate::navigationMode = mode;
+}
+#endif
+
+#ifndef QT_NO_CURSOR
+/*****************************************************************************
+ QApplication cursor stack
+ *****************************************************************************/
+
+void QApplication::setOverrideCursor(const QCursor &cursor)
+{
+    qApp->d_func()->cursor_list.prepend(cursor);
+    qt_symbian_setGlobalCursor(cursor);
+}
+
+void QApplication::restoreOverrideCursor()
+{
+    if (qApp->d_func()->cursor_list.isEmpty())
+        return;
+    qApp->d_func()->cursor_list.removeFirst();
+
+    if (!qApp->d_func()->cursor_list.isEmpty()) {
+        qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first());
+    }
+    else {
+        //determine which widget has focus
+        QWidget *w = QApplication::widgetAt(QCursor::pos());
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+        if (S60->brokenPointerCursors) {
+            qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor);
+        }
+        else
+#endif
+        {
+            //because of the internals of window server, we need to force the cursor
+            //to be set in all child windows too, otherwise when the cursor is over
+            //the child window it may show a widget cursor or arrow cursor instead,
+            //depending on construction order.
+            QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys());
+            while (iter.hasNext()) {
+                CCoeControl *ctrl = iter.next();
+                if(ctrl->OwnsWindow()) {
+                    ctrl->DrawableWindow()->ClearPointerCursor();
+                }
+            }
+            if (w)
+                qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId());
+            else
+                qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
+        }
+    }
+}
+
+#endif // QT_NO_CURSOR
+
+QT_END_NAMESPACE