<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (<EMAIL>)
**
** 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 <EMAIL>.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qapplication_p.h"
#include "qsessionmanager.h"
#include "qevent.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;
    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));
}

void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
{
    //### refactor me, getting too complex
    QMouseEvent::Type type;
    Qt::MouseButton button;
    mapS60MouseEventTypeToQt(&type, &button, &pEvent);

    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
    QWidget *alienWidget;
    typedef QPair<QWidget*,QMouseEvent> Event;
    QList<Event > events;

    QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY);
    TPoint controlScreenPos = PositionRelativeToScreen();
    QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;

    if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)
    {
        // get the widget where the event happened
        alienWidget = qwidget->childAt(widgetPos);
        if (!alienWidget)
            alienWidget = qwidget;
        S60->mousePressTarget = alienWidget;
    }

    alienWidget = S60->mousePressTarget;

    if (alienWidget != S60->lastPointerEventTarget)
        if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)
        {
            //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, mapToQtModifiers(pEvent.iModifiers));
                events.append(Event(S60->lastPointerEventTarget,mEventLeave));
            }
            if (alienWidget) {
                QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos),
                    globalPos, button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(
                        pEvent.iModifiers));

                events.append(Event(alienWidget, mEventEnter));
#ifndef QT_NO_CURSOR
                S60->curWin = alienWidget->effectiveWinId();
                if (!QApplication::overrideCursor()) {
#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
                    if (S60->brokenPointerCursors)
                        qt_symbian_set_pointer_sprite(alienWidget->cursor());
                    else
#endif
                        qt_symbian_setWindowCursor(alienWidget->cursor(), S60->curWin);
                }
#endif
            }
        }
    S60->lastCursorPos = globalPos;
#if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS)
    if (S60->brokenPointerCursors)
        qt_symbian_move_cursor_sprite();
#endif
    S60->lastPointerEventPos = widgetPos;
    S60->lastPointerEventTarget = alienWidget;
    if (alienWidget)
    {
        QMouseEvent mEvent(type, alienWidget->mapFromGlobal(globalPos), globalPos,
            button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers));
        events.append(Event(alienWidget,mEvent));
        QEventDispatcherS60 *dispatcher;
        // It is theoretically possible for someone to install a different event dispatcher.
        if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(alienWidget->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;
            }
        }
    }
    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, mods);
//        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));
        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 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->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);

    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;
    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)
        touch = 0;
    if (mouse || machineUID == KMachineUidSamsungI8510) {
        S60->hasTouchscreen = false;
        S60->virtualMouseRequired = false;
    }
    else if (!touch) {
        S60->hasTouchscreen = false;
        S60->virtualMouseRequired = true;
    }
    else {
        S60->hasTouchscreen = true;<commit_msg>Fixing Keypad Navigation on N95 devices<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (<EMAIL>)
**
** 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 <EMAIL>.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qapplication_p.h"
#include "qsessionmanager.h"
#include "qevent.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;
    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));
}

void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
{
    //### refactor me, getting too complex
    QMouseEvent::Type type;
    Qt::MouseButton button;
    mapS60MouseEventTypeToQt(&type, &button, &pEvent);

    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
    QWidget *alienWidget;
    typedef QPair<QWidget*,QMouseEvent> Event;
    QList<Event > events;

    QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY);
    TPoint controlScreenPos = PositionRelativeToScreen();
    QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;

    if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)
    {
        // get the widget where the event happened
        alienWidget = qwidget->childAt(widgetPos);
        if (!alienWidget)
            alienWidget = qwidget;
        S60->mousePressTarget = alienWidget;
    }

    alienWidget = S60->mousePressTarget;

    if (alienWidget != S60->lastPointerEventTarget)
        if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)
        {
            //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, mapToQtModifiers(pEvent.iModifiers));
                events.append(Event(S60->lastPointerEventTarget,mEventLeave));
            }
            if (alienWidget) {
                QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos),
                    globalPos, button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(
                        pEvent.iModifiers));

                events.append(Event(alienWidget, mEventEnter));
#ifndef QT_NO_CURSOR
                S60->curWin = alienWidget->effectiveWinId();
                if (!QApplication::overrideCursor()) {
#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
                    if (S60->brokenPointerCursors)
                        qt_symbian_set_pointer_sprite(alienWidget->cursor());
                    else
#endif
                        qt_symbian_setWindowCursor(alienWidget->cursor(), S60->curWin);
                }
#endif
            }
        }
    S60->lastCursorPos = globalPos;
#if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS)
    if (S60->brokenPointerCursors)
        qt_symbian_move_cursor_sprite();
#endif
    S60->lastPointerEventPos = widgetPos;
    S60->lastPointerEventTarget = alienWidget;
    if (alienWidget)
    {
        QMouseEvent mEvent(type, alienWidget->mapFromGlobal(globalPos), globalPos,
            button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers));
        events.append(Event(alienWidget,mEvent));
        QEventDispatcherS60 *dispatcher;
        // It is theoretically possible for someone to install a different event dispatcher.
        if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(alienWidget->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;
            }
        }
    }
    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, mods);
//        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));
        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 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->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);

    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;
    if (mouse || machineUID == KMachineUidSamsungI8510) {
        S60->hasTouchscreen = false;
        S60->virtualMouseRequired = false;
    }
    else if (!touch) {
        S60->hasTouchscreen = false;
        S60->virtualMouseRequired = true;
    }
    else {
        S60->hasTouchscreen = true;
{'fraction_non_alphanumeric': 0.10876821405112669, 'fraction_numerical': 0.011273609565811873, 'mean_word_length': 2.726646018583275, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 447, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6522213', 'n_tokens_mistral': 22858, 'n_tokens_neox': 21882, 'n_words': 4821}