breakdeps/gui/kernel/qapplication_s60.cpp
changeset 136 4c8d6b2fb1da
equal deleted inserted replaced
66:fc9981c83de7 136:4c8d6b2fb1da
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qapplication_p.h"
       
    43 #include "qsessionmanager.h"
       
    44 #include "qevent.h"
       
    45 #include "qsymbianevent.h"
       
    46 #include "qeventdispatcher_s60_p.h"
       
    47 #include "qwidget.h"
       
    48 #include "qdesktopwidget.h"
       
    49 #include "private/qbackingstore_p.h"
       
    50 #include "qt_s60_p.h"
       
    51 #include "private/qevent_p.h"
       
    52 #include "qstring.h"
       
    53 #include "qdebug.h"
       
    54 #include "qimage.h"
       
    55 #include "qcombobox.h"
       
    56 #include "private/qkeymapper_p.h"
       
    57 #include "private/qfont_p.h"
       
    58 #ifndef QT_NO_STYLE_S60
       
    59 #include "private/qs60style_p.h"
       
    60 #endif
       
    61 #include "private/qwindowsurface_s60_p.h"
       
    62 #include "qpaintengine.h"
       
    63 #include "private/qmenubar_p.h"
       
    64 #include "private/qsoftkeymanager_p.h"
       
    65 
       
    66 #include "apgwgnam.h" // For CApaWindowGroupName
       
    67 #include <mdaaudiotoneplayer.h>     // For CMdaAudioToneUtility
       
    68 
       
    69 #if defined(Q_WS_S60)
       
    70 # if !defined(QT_NO_IM)
       
    71 #  include "qinputcontext.h"
       
    72 #  include <private/qcoefepinputcontext_p.h>
       
    73 # endif
       
    74 # include <private/qs60mainapplication_p.h>
       
    75 # include <centralrepository.h>
       
    76 # include "qs60mainappui.h"
       
    77 #endif
       
    78 
       
    79 #include "private/qstylesheetstyle_p.h"
       
    80 
       
    81 #include <hal.h>
       
    82 #include <hal_data.h>
       
    83 
       
    84 QT_BEGIN_NAMESPACE
       
    85 
       
    86 #if defined(QT_DEBUG)
       
    87 static bool        appNoGrab        = false;        // Grabbing enabled
       
    88 #endif
       
    89 static bool        app_do_modal        = false;        // modal mode
       
    90 Q_GLOBAL_STATIC(QS60Data, qt_s60Data);
       
    91 
       
    92 extern bool qt_sendSpontaneousEvent(QObject*,QEvent*);
       
    93 extern QWidgetList *qt_modal_stack;              // stack of modal widgets
       
    94 extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
       
    95 
       
    96 QWidget *qt_button_down = 0;                     // widget got last button-down
       
    97 
       
    98 QSymbianControl *QSymbianControl::lastFocusedControl = 0;
       
    99 
       
   100 QS60Data* qGlobalS60Data()
       
   101 {
       
   102     return qt_s60Data();
       
   103 }
       
   104 
       
   105 bool qt_nograb()                                // application no-grab option
       
   106 {
       
   107 #if defined(QT_DEBUG)
       
   108     return appNoGrab;
       
   109 #else
       
   110     return false;
       
   111 #endif
       
   112 }
       
   113 
       
   114 // Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument
       
   115 class QS60Beep : public CBase, public MMdaAudioToneObserver
       
   116 {
       
   117 public:
       
   118     static QS60Beep* NewL(TInt aFrequency,  TTimeIntervalMicroSeconds iDuration);
       
   119     void Play();
       
   120     ~QS60Beep();
       
   121 private:
       
   122     void ConstructL(TInt aFrequency,  TTimeIntervalMicroSeconds iDuration);
       
   123     void MatoPrepareComplete(TInt aError);
       
   124     void MatoPlayComplete(TInt aError);
       
   125 private:
       
   126     typedef enum
       
   127         {
       
   128         EBeepNotPrepared,
       
   129         EBeepPrepared,
       
   130         EBeepPlaying
       
   131         } TBeepState;
       
   132 private:
       
   133     CMdaAudioToneUtility* iToneUtil;
       
   134     TBeepState iState;
       
   135     TInt iFrequency;
       
   136     TTimeIntervalMicroSeconds iDuration;
       
   137 };
       
   138 
       
   139 static QS60Beep* qt_S60Beep = 0;
       
   140 
       
   141 QS60Beep::~QS60Beep()
       
   142 {
       
   143     if (iToneUtil) {
       
   144         switch (iState) {
       
   145         case EBeepPlaying:
       
   146             iToneUtil->CancelPlay();
       
   147             break;
       
   148         case EBeepNotPrepared:
       
   149             iToneUtil->CancelPrepare();
       
   150             break;
       
   151         }
       
   152     }
       
   153     delete iToneUtil;
       
   154 }
       
   155 
       
   156 QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
       
   157 {
       
   158     QS60Beep* self = new (ELeave) QS60Beep();
       
   159     CleanupStack::PushL(self);
       
   160     self->ConstructL(aFrequency, aDuration);
       
   161     CleanupStack::Pop();
       
   162     return self;
       
   163 }
       
   164 
       
   165 void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
       
   166 {
       
   167     iToneUtil = CMdaAudioToneUtility::NewL(*this);
       
   168     iState = EBeepNotPrepared;
       
   169     iFrequency = aFrequency;
       
   170     iDuration = aDuration;
       
   171     iToneUtil->PrepareToPlayTone(iFrequency, iDuration);
       
   172 }
       
   173 
       
   174 void QS60Beep::Play()
       
   175 {
       
   176     if (iState == EBeepPlaying) {
       
   177         iToneUtil->CancelPlay();
       
   178         iState = EBeepPrepared;
       
   179     }
       
   180 
       
   181     iToneUtil->Play();
       
   182     iState = EBeepPlaying;
       
   183 }
       
   184 
       
   185 void QS60Beep::MatoPrepareComplete(TInt aError)
       
   186 {
       
   187     if (aError == KErrNone) {
       
   188         iState = EBeepPrepared;
       
   189         Play();
       
   190     }
       
   191 }
       
   192 
       
   193 void QS60Beep::MatoPlayComplete(TInt aError)
       
   194 {
       
   195     Q_UNUSED(aError);
       
   196     iState = EBeepPrepared;
       
   197 }
       
   198 
       
   199 
       
   200 QHash<TInt, TUint> QApplicationPrivate::scanCodeCache;
       
   201 
       
   202 static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers)
       
   203 {
       
   204     Qt::KeyboardModifiers result = Qt::NoModifier;
       
   205 
       
   206     if (s60Modifiers & EModifierKeypad)
       
   207         result |= Qt::KeypadModifier;
       
   208     if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift
       
   209             || s60Modifiers & EModifierRightShift)
       
   210         result |= Qt::ShiftModifier;
       
   211     if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl
       
   212             || s60Modifiers & EModifierRightCtrl)
       
   213         result |= Qt::ControlModifier;
       
   214     if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt
       
   215             || s60Modifiers & EModifierRightAlt)
       
   216         result |= Qt::AltModifier;
       
   217 
       
   218     return result;
       
   219 }
       
   220 
       
   221 static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent)
       
   222 {
       
   223     switch (pEvent->iType) {
       
   224     case TPointerEvent::EButton1Down:
       
   225         *type = QEvent::MouseButtonPress;
       
   226         *button = Qt::LeftButton;
       
   227         break;
       
   228     case TPointerEvent::EButton1Up:
       
   229         *type = QEvent::MouseButtonRelease;
       
   230         *button = Qt::LeftButton;
       
   231         break;
       
   232     case TPointerEvent::EButton2Down:
       
   233         *type = QEvent::MouseButtonPress;
       
   234         *button = Qt::MidButton;
       
   235         break;
       
   236     case TPointerEvent::EButton2Up:
       
   237         *type = QEvent::MouseButtonRelease;
       
   238         *button = Qt::MidButton;
       
   239         break;
       
   240     case TPointerEvent::EButton3Down:
       
   241         *type = QEvent::MouseButtonPress;
       
   242         *button = Qt::RightButton;
       
   243         break;
       
   244     case TPointerEvent::EButton3Up:
       
   245         *type = QEvent::MouseButtonRelease;
       
   246         *button = Qt::RightButton;
       
   247         break;
       
   248     case TPointerEvent::EDrag:
       
   249         *type = QEvent::MouseMove;
       
   250         *button = Qt::NoButton;
       
   251         break;
       
   252     case TPointerEvent::EMove:
       
   253         // Qt makes no distinction between move and drag
       
   254         *type = QEvent::MouseMove;
       
   255         *button = Qt::NoButton;
       
   256         break;
       
   257     default:
       
   258         *type = QEvent::None;
       
   259         *button = Qt::NoButton;
       
   260         break;
       
   261     }
       
   262     if (pEvent->iModifiers & EModifierDoubleClick){
       
   263         *type = QEvent::MouseButtonDblClick;
       
   264     }
       
   265 
       
   266     if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick)
       
   267         QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button);
       
   268     else if (*type == QEvent::MouseButtonRelease)
       
   269         QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button));
       
   270 
       
   271     QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask;
       
   272 }
       
   273 
       
   274 //### Can be replaced with CAknLongTapDetector if animation is required.
       
   275 //NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,.
       
   276 //also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used.
       
   277 class QLongTapTimer : public CTimer
       
   278 {
       
   279 public:
       
   280     static QLongTapTimer* NewL(QAbstractLongTapObserver *observer);
       
   281     QLongTapTimer(QAbstractLongTapObserver *observer);
       
   282     void ConstructL();
       
   283 public:
       
   284     void PointerEventL(const TPointerEvent &event);
       
   285     void RunL();
       
   286 protected:
       
   287 private:
       
   288     QAbstractLongTapObserver *m_observer;
       
   289     TPointerEvent m_event;
       
   290     QPoint m_pressedCoordinates;
       
   291     int m_dragDistance;
       
   292 };
       
   293 
       
   294 QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer)
       
   295 {
       
   296     QLongTapTimer* self = new QLongTapTimer(observer);
       
   297     self->ConstructL();
       
   298     return self;
       
   299 }
       
   300 void QLongTapTimer::ConstructL()
       
   301 {
       
   302     CTimer::ConstructL();
       
   303 }
       
   304 
       
   305 QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh)
       
   306 {
       
   307     m_observer = observer;
       
   308     m_dragDistance = qApp->startDragDistance();
       
   309     CActiveScheduler::Add(this);
       
   310 }
       
   311 
       
   312 void QLongTapTimer::PointerEventL(const TPointerEvent& event)
       
   313 {
       
   314     if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat)
       
   315     {
       
   316         QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates);
       
   317         if (diff.manhattanLength() < m_dragDistance)
       
   318             return;
       
   319     }
       
   320     Cancel();
       
   321     m_event = event;
       
   322     if (event.iType == TPointerEvent::EButton1Down)
       
   323     {
       
   324         m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY);
       
   325         // must be same as KLongTapDelay in aknlongtapdetector.h
       
   326         After(800000);
       
   327     }
       
   328 }
       
   329 void QLongTapTimer::RunL()
       
   330 {
       
   331     if (m_observer)
       
   332         m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition);
       
   333 }
       
   334 
       
   335 QSymbianControl::QSymbianControl(QWidget *w)
       
   336     : CCoeControl()
       
   337     , qwidget(w)
       
   338     , m_longTapDetector(0)
       
   339     , m_ignoreFocusChanged(0)
       
   340     , m_symbianPopupIsOpen(0)
       
   341 {
       
   342 }
       
   343 
       
   344 void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
       
   345 {
       
   346     if (!desktop)
       
   347     {
       
   348         if (isWindowOwning or !qwidget->parentWidget())
       
   349             CreateWindowL(S60->windowGroup());
       
   350         else
       
   351             /**
       
   352              * TODO: in order to avoid creating windows for all ancestors of
       
   353              * this widget up to the root window, the parameter passed to
       
   354              * CreateWindowL should be
       
   355              * qwidget->parentWidget()->effectiveWinId().  However, if we do
       
   356              * this, then we need to take care of re-parenting when a window
       
   357              * is created for a widget between this one and the root window.
       
   358              */
       
   359             CreateWindowL(qwidget->parentWidget()->winId());
       
   360 
       
   361         // Necessary in order to be able to track the activation status of
       
   362         // the control's window
       
   363         qwidget->d_func()->createExtra();
       
   364 
       
   365         SetFocusing(true);
       
   366         m_longTapDetector = QLongTapTimer::NewL(this);
       
   367 
       
   368         DrawableWindow()->SetPointerGrab(ETrue);
       
   369     }
       
   370 }
       
   371 
       
   372 QSymbianControl::~QSymbianControl()
       
   373 {
       
   374     if (S60->curWin == this)
       
   375         S60->curWin = 0;
       
   376     if (!QApplicationPrivate::is_app_closing) {
       
   377         QT_TRY {
       
   378             setFocusSafely(false);
       
   379         } QT_CATCH(const std::exception&) {
       
   380             // ignore exceptions, nothing can be done
       
   381         }
       
   382     }
       
   383     S60->appUi()->RemoveFromStack(this);
       
   384     delete m_longTapDetector;
       
   385 }
       
   386 
       
   387 void QSymbianControl::setWidget(QWidget *w)
       
   388 {
       
   389     qwidget = w;
       
   390 }
       
   391 void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation )
       
   392 {
       
   393     QWidget *alienWidget;
       
   394     QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY);
       
   395     QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY);
       
   396     alienWidget = qwidget->childAt(widgetPos);
       
   397     if (!alienWidget)
       
   398         alienWidget = qwidget;
       
   399 
       
   400 #if !defined(QT_NO_CONTEXTMENU)
       
   401     QContextMenuEvent contextMenuEvent(QContextMenuEvent::Mouse, widgetPos, globalPos, Qt::NoModifier);
       
   402     qt_sendSpontaneousEvent(alienWidget, &contextMenuEvent);
       
   403 #endif
       
   404 }
       
   405 
       
   406 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
       
   407 void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event)
       
   408 {
       
   409     QApplicationPrivate *d = QApplicationPrivate::instance();
       
   410 
       
   411     QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget);
       
   412 
       
   413     while (d->appAllTouchPoints.count() <= event->PointerNumber())
       
   414         d->appAllTouchPoints.append(QTouchEvent::TouchPoint(d->appAllTouchPoints.count()));
       
   415 
       
   416     Qt::TouchPointStates allStates = 0;
       
   417     for (int i = 0; i < d->appAllTouchPoints.count(); ++i) {
       
   418         QTouchEvent::TouchPoint &touchPoint = d->appAllTouchPoints[i];
       
   419 
       
   420         if (touchPoint.id() == event->PointerNumber()) {
       
   421             Qt::TouchPointStates state;
       
   422             switch (event->iType) {
       
   423             case TPointerEvent::EButton1Down:
       
   424             case TPointerEvent::EEnterHighPressure:
       
   425                 state = Qt::TouchPointPressed;
       
   426                 break;
       
   427             case TPointerEvent::EButton1Up:
       
   428             case TPointerEvent::EExitCloseProximity:
       
   429                 state = Qt::TouchPointReleased;
       
   430                 break;
       
   431             case TPointerEvent::EDrag:
       
   432                 state = Qt::TouchPointMoved;
       
   433                 break;
       
   434             default:
       
   435                 // how likely is this to happen?
       
   436                 state = Qt::TouchPointStationary;
       
   437                 break;
       
   438             }
       
   439             if (event->PointerNumber() == 0)
       
   440                 state |= Qt::TouchPointPrimary;
       
   441             touchPoint.setState(state);
       
   442 
       
   443             QPointF screenPos = qwidget->mapToGlobal(QPoint(event->iPosition.iX, event->iPosition.iY));
       
   444             touchPoint.setScreenPos(screenPos);
       
   445             touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(),
       
   446                                                 screenPos.y() / screenGeometry.height()));
       
   447 
       
   448             touchPoint.setPressure(event->Pressure() / qreal(d->maxTouchPressure));
       
   449         } else if (touchPoint.state() != Qt::TouchPointReleased) {
       
   450             // all other active touch points should be marked as stationary
       
   451             touchPoint.setState(Qt::TouchPointStationary);
       
   452         }
       
   453 
       
   454         allStates |= touchPoint.state();
       
   455     }
       
   456 
       
   457     if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) {
       
   458         // all touch points released
       
   459         d->appAllTouchPoints.clear();
       
   460     }
       
   461 
       
   462     QApplicationPrivate::translateRawTouchEvent(qwidget,
       
   463                                                 QTouchEvent::TouchScreen,
       
   464                                                 d->appAllTouchPoints);
       
   465 }
       
   466 #endif
       
   467 
       
   468 void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent)
       
   469 {
       
   470 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
       
   471     if (pEvent.IsAdvancedPointerEvent()) {
       
   472         const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent();
       
   473         translateAdvancedPointerEvent(advancedPointerEvent);
       
   474         if (advancedPointerEvent->PointerNumber() != 0) {
       
   475             // only send mouse events for the first touch point
       
   476             return;
       
   477         }
       
   478     }
       
   479 #endif
       
   480 
       
   481     m_longTapDetector->PointerEventL(pEvent);
       
   482     QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent));
       
   483 }
       
   484 
       
   485 void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
       
   486 {
       
   487     QMouseEvent::Type type;
       
   488     Qt::MouseButton button;
       
   489     mapS60MouseEventTypeToQt(&type, &button, &pEvent);
       
   490     Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers);
       
   491 
       
   492     QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY);
       
   493     TPoint controlScreenPos = PositionRelativeToScreen();
       
   494     QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;
       
   495     S60->lastCursorPos = globalPos;
       
   496     S60->lastPointerEventPos = widgetPos;
       
   497 
       
   498     QWidget *mouseGrabber = QWidget::mouseGrabber();
       
   499 
       
   500     QWidget *popupWidget = qApp->activePopupWidget();
       
   501     QWidget *popupReceiver = 0;
       
   502     if (popupWidget) {
       
   503         QWidget *popupChild = popupWidget->childAt(popupWidget->mapFromGlobal(globalPos));
       
   504         popupReceiver = popupChild ? popupChild : popupWidget;
       
   505     }
       
   506 
       
   507     if (mouseGrabber) {
       
   508         if (popupReceiver) {
       
   509             sendMouseEvent(popupReceiver, type, globalPos, button, modifiers);
       
   510         } else {
       
   511             sendMouseEvent(mouseGrabber, type, globalPos, button, modifiers);
       
   512         }
       
   513         // No Enter/Leave events in grabbing mode.
       
   514         return;
       
   515     }
       
   516 
       
   517     QWidget *widgetUnderPointer = qwidget->childAt(widgetPos);
       
   518     if (!widgetUnderPointer)
       
   519         widgetUnderPointer = qwidget;
       
   520 
       
   521     QApplicationPrivate::dispatchEnterLeave(widgetUnderPointer, S60->lastPointerEventTarget);
       
   522     S60->lastPointerEventTarget = widgetUnderPointer;
       
   523 
       
   524     QWidget *receiver;
       
   525     if (!popupReceiver && S60->mousePressTarget && type != QEvent::MouseButtonPress) {
       
   526         receiver = S60->mousePressTarget;
       
   527         if (type == QEvent::MouseButtonRelease)
       
   528             S60->mousePressTarget = 0;
       
   529     } else {
       
   530         receiver = popupReceiver ? popupReceiver : widgetUnderPointer;
       
   531         if (type == QEvent::MouseButtonPress)
       
   532             S60->mousePressTarget = receiver;
       
   533     }
       
   534 
       
   535 #if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS)
       
   536     if (S60->brokenPointerCursors)
       
   537         qt_symbian_move_cursor_sprite();
       
   538 #endif
       
   539 
       
   540     sendMouseEvent(receiver, type, globalPos, button, modifiers);
       
   541 }
       
   542 
       
   543 #ifdef Q_WS_S60
       
   544 void QSymbianControl::HandleStatusPaneSizeChange()
       
   545 {
       
   546     QS60MainAppUi *s60AppUi = static_cast<QS60MainAppUi *>(S60->appUi());
       
   547     s60AppUi->HandleStatusPaneSizeChange();
       
   548 }
       
   549 #endif
       
   550 
       
   551 void QSymbianControl::sendMouseEvent(
       
   552         QWidget *receiver,
       
   553         QEvent::Type type,
       
   554         const QPoint &globalPos,
       
   555         Qt::MouseButton button,
       
   556         Qt::KeyboardModifiers modifiers)
       
   557 {
       
   558     Q_ASSERT(receiver);
       
   559     QMouseEvent mEvent(type, receiver->mapFromGlobal(globalPos), globalPos,
       
   560         button, QApplicationPrivate::mouse_buttons, modifiers);
       
   561     QEventDispatcherS60 *dispatcher;
       
   562     // It is theoretically possible for someone to install a different event dispatcher.
       
   563     if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(receiver->d_func()->threadData->eventDispatcher)) != 0) {
       
   564         if (dispatcher->excludeUserInputEvents()) {
       
   565             dispatcher->saveInputEvent(this, receiver, new QMouseEvent(mEvent));
       
   566             return;
       
   567         }
       
   568     }
       
   569 
       
   570     sendMouseEvent(receiver, &mEvent);
       
   571 }
       
   572 
       
   573 bool QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent)
       
   574 {
       
   575     return qt_sendSpontaneousEvent(widget, mEvent);
       
   576 }
       
   577 
       
   578 TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type)
       
   579 {
       
   580     TKeyResponse r = EKeyWasNotConsumed;
       
   581     QT_TRYCATCH_LEAVING(r = OfferKeyEvent(keyEvent, type));
       
   582     return r;
       
   583 }
       
   584 
       
   585 TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type)
       
   586 {
       
   587     switch (type) {
       
   588     //case EEventKeyDown: // <-- Intentionally left out. See below.
       
   589     case EEventKeyUp:
       
   590     case EEventKey:
       
   591     {
       
   592         // S60 has a confusing way of delivering key events. There are three types of
       
   593         // events: EKeyEvent, EKeyEventDown and EKeyEventUp. When a key is pressed, the
       
   594         // two first events are generated. When releasing the key, the last one is
       
   595         // generated.
       
   596         // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp events,
       
   597         // we need to do some special tricks to map it to the Qt way. First, we completely
       
   598         // discard EKeyEventDown events, since they are redundant. Second, since
       
   599         // EKeyEventUp does not give us a keysym, we need to cache the keysyms from
       
   600         // the EKeyEvent events. This is what resolveS60ScanCode does.
       
   601 
       
   602 
       
   603         // ### hackish way to send Qt application to background when pressing right softkey
       
   604         /*
       
   605         if( keyEvent.iScanCode == EStdKeyDevice1 ) {
       
   606             S60->window_group->SetOrdinalPosition(-1);
       
   607             qApp->setActiveWindow(0);
       
   608             return EKeyWasNotConsumed;
       
   609         }
       
   610         */
       
   611 
       
   612         TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode,
       
   613                 keyEvent.iCode);
       
   614         int keyCode;
       
   615         if (s60Keysym == EKeyNull){ //some key events have 0 in iCode, for them iScanCode should be used
       
   616             keyCode = qt_keymapper_private()->mapS60ScanCodesToQt(keyEvent.iScanCode);
       
   617         } else if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) {
       
   618             // Normal characters keys.
       
   619             keyCode = s60Keysym;
       
   620         } else {
       
   621             // Special S60 keys.
       
   622             keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym);
       
   623         }
       
   624 
       
   625 #ifndef QT_NO_CURSOR
       
   626         if (S60->mouseInteractionEnabled && S60->virtualMouseRequired) {
       
   627             //translate keys to pointer
       
   628             if (keyCode >= Qt::Key_Left && keyCode <= Qt::Key_Down || keyCode == Qt::Key_Select) {
       
   629                 /*Explanation about virtualMouseAccel:
       
   630                  Tapping an arrow key allows precise pixel positioning
       
   631                  Holding an arrow key down, acceleration is applied to allow cursor
       
   632                  to be quickly moved to another part of the screen by key repeats.
       
   633                  */
       
   634                 if (S60->virtualMouseLastKey == keyCode) {
       
   635                     S60->virtualMouseAccel *= 2;
       
   636                     if (S60->virtualMouseAccel > S60->virtualMouseMaxAccel)
       
   637                         S60->virtualMouseAccel = S60->virtualMouseMaxAccel;
       
   638                 }
       
   639                 else
       
   640                     S60->virtualMouseAccel = 1;
       
   641                 S60->virtualMouseLastKey = keyCode;
       
   642 
       
   643                 QPoint pos = QCursor::pos();
       
   644                 TPointerEvent fakeEvent;
       
   645                 TInt x = pos.x();
       
   646                 TInt y = pos.y();
       
   647                 if (type == EEventKeyUp) {
       
   648                     if (keyCode == Qt::Key_Select)
       
   649                         fakeEvent.iType = TPointerEvent::EButton1Up;
       
   650                     S60->virtualMouseAccel = 1;
       
   651                     S60->virtualMouseLastKey = 0;
       
   652                     switch (keyCode) {
       
   653                     case Qt::Key_Left:
       
   654                         S60->virtualMousePressedKeys &= ~QS60Data::Left;
       
   655                         break;
       
   656                     case Qt::Key_Right:
       
   657                         S60->virtualMousePressedKeys &= ~QS60Data::Right;
       
   658                         break;
       
   659                     case Qt::Key_Up:
       
   660                         S60->virtualMousePressedKeys &= ~QS60Data::Up;
       
   661                         break;
       
   662                     case Qt::Key_Down:
       
   663                         S60->virtualMousePressedKeys &= ~QS60Data::Down;
       
   664                         break;
       
   665                     case Qt::Key_Select:
       
   666                         S60->virtualMousePressedKeys &= ~QS60Data::Select;
       
   667                         break;
       
   668                     }
       
   669                 }
       
   670                 else if (type == EEventKey) {
       
   671                     switch (keyCode) {
       
   672                     case Qt::Key_Left:
       
   673                         S60->virtualMousePressedKeys |= QS60Data::Left;
       
   674                         x -= S60->virtualMouseAccel;
       
   675                         fakeEvent.iType = TPointerEvent::EMove;
       
   676                         break;
       
   677                     case Qt::Key_Right:
       
   678                         S60->virtualMousePressedKeys |= QS60Data::Right;
       
   679                         x += S60->virtualMouseAccel;
       
   680                         fakeEvent.iType = TPointerEvent::EMove;
       
   681                         break;
       
   682                     case Qt::Key_Up:
       
   683                         S60->virtualMousePressedKeys |= QS60Data::Up;
       
   684                         y -= S60->virtualMouseAccel;
       
   685                         fakeEvent.iType = TPointerEvent::EMove;
       
   686                         break;
       
   687                     case Qt::Key_Down:
       
   688                         S60->virtualMousePressedKeys |= QS60Data::Down;
       
   689                         y += S60->virtualMouseAccel;
       
   690                         fakeEvent.iType = TPointerEvent::EMove;
       
   691                         break;
       
   692                     case Qt::Key_Select:
       
   693                         // Platform bug. If you start pressing several keys simultaneously (for
       
   694                         // example for drag'n'drop), Symbian starts producing spurious up and
       
   695                         // down messages for some keys. Therefore, make sure we have a clean slate
       
   696                         // of pressed keys before starting a new button press.
       
   697                         if (S60->virtualMousePressedKeys != 0) {
       
   698                             S60->virtualMousePressedKeys |= QS60Data::Select;
       
   699                             return EKeyWasConsumed;
       
   700                         } else {
       
   701                             S60->virtualMousePressedKeys |= QS60Data::Select;
       
   702                             fakeEvent.iType = TPointerEvent::EButton1Down;
       
   703                         }
       
   704                         break;
       
   705                     }
       
   706                 }
       
   707                 //clip to screen size (window server allows a sprite hotspot to be outside the screen)
       
   708                 if (x < 0)
       
   709                     x = 0;
       
   710                 else if (x >= S60->screenWidthInPixels)
       
   711                     x = S60->screenWidthInPixels - 1;
       
   712                 if (y < 0)
       
   713                     y = 0;
       
   714                 else if (y >= S60->screenHeightInPixels)
       
   715                     y = S60->screenHeightInPixels - 1;
       
   716                 TPoint epos(x, y);
       
   717                 TPoint cpos = epos - PositionRelativeToScreen();
       
   718                 fakeEvent.iModifiers = keyEvent.iModifiers;
       
   719                 fakeEvent.iPosition = cpos;
       
   720                 fakeEvent.iParentPosition = epos;
       
   721                 HandlePointerEvent(fakeEvent);
       
   722                 return EKeyWasConsumed;
       
   723             }
       
   724             else {
       
   725                 S60->virtualMouseLastKey = keyCode;
       
   726                 S60->virtualMouseAccel = 1;
       
   727             }
       
   728         }
       
   729 #endif
       
   730 
       
   731         Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers);
       
   732         QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode,
       
   733                 mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods),
       
   734                 (keyEvent.iRepeats != 0), 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers);
       
   735 //        WId wid = reinterpret_cast<RWindowGroup *>(keyEvent.Handle())->Child();
       
   736 //        if (!wid)
       
   737 //             Could happen if window isn't shown yet.
       
   738 //            return EKeyWasNotConsumed;
       
   739         QWidget *widget;
       
   740         widget = QWidget::keyboardGrabber();
       
   741         if (!widget) {
       
   742             if (QApplicationPrivate::popupWidgets != 0) {
       
   743                 widget = QApplication::activePopupWidget()->focusWidget();
       
   744                 if (!widget) {
       
   745                     widget = QApplication::activePopupWidget();
       
   746                 }
       
   747             } else {
       
   748                 widget = QApplicationPrivate::focus_widget;
       
   749                 if (!widget) {
       
   750                     widget = qwidget;
       
   751                 }
       
   752             }
       
   753         }
       
   754 
       
   755         QEventDispatcherS60 *dispatcher;
       
   756         // It is theoretically possible for someone to install a different event dispatcher.
       
   757         if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) != 0) {
       
   758             if (dispatcher->excludeUserInputEvents()) {
       
   759                 dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent));
       
   760                 return EKeyWasConsumed;
       
   761             }
       
   762         }
       
   763         return sendKeyEvent(widget, &qKeyEvent);
       
   764     }
       
   765     }
       
   766     return EKeyWasNotConsumed;
       
   767 }
       
   768 
       
   769 void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent)
       
   770 {
       
   771     switch (inputEvent->type()) {
       
   772     case QEvent::KeyPress:
       
   773     case QEvent::KeyRelease:
       
   774         sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent));
       
   775         break;
       
   776     case QEvent::MouseButtonDblClick:
       
   777     case QEvent::MouseButtonPress:
       
   778     case QEvent::MouseButtonRelease:
       
   779     case QEvent::MouseMove:
       
   780         sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent));
       
   781         break;
       
   782     default:
       
   783         // Shouldn't get here.
       
   784         Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown");
       
   785         break;
       
   786     }
       
   787 }
       
   788 
       
   789 TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent)
       
   790 {
       
   791 #if !defined(QT_NO_IM) && defined(Q_WS_S60)
       
   792     if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) {
       
   793         QInputContext *qic = widget->inputContext();
       
   794         if (qic && qic->filterEvent(keyEvent))
       
   795             return EKeyWasConsumed;
       
   796     }
       
   797 #endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
       
   798 
       
   799     if (widget && qt_sendSpontaneousEvent(widget, keyEvent))
       
   800         if (keyEvent->isAccepted())
       
   801             return EKeyWasConsumed;
       
   802 
       
   803     return EKeyWasNotConsumed;
       
   804 }
       
   805 
       
   806 #if !defined(QT_NO_IM) && defined(Q_WS_S60)
       
   807 TCoeInputCapabilities QSymbianControl::InputCapabilities() const
       
   808 {
       
   809     QWidget *w = 0;
       
   810 
       
   811     if (qwidget->hasFocus())
       
   812         w = qwidget;
       
   813     else
       
   814         w = qwidget->focusWidget();
       
   815 
       
   816     QCoeFepInputContext *ic;
       
   817     if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled)
       
   818             && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) {
       
   819         return ic->inputCapabilities();
       
   820     } else {
       
   821         return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0);
       
   822     }
       
   823 }
       
   824 #endif
       
   825 
       
   826 void QSymbianControl::Draw(const TRect& controlRect) const
       
   827 {
       
   828     // Set flag to avoid calling DrawNow in window surface
       
   829     QWidget *window = qwidget->window();
       
   830     Q_ASSERT(window);
       
   831     QTLWExtra *topExtra = window->d_func()->maybeTopData();
       
   832     Q_ASSERT(topExtra);
       
   833     if (!topExtra->inExpose) {
       
   834         topExtra->inExpose = true;
       
   835         QRect exposeRect = qt_TRect2QRect(controlRect);
       
   836         qwidget->d_func()->syncBackingStore(exposeRect);
       
   837         topExtra->inExpose = false;
       
   838     }
       
   839 
       
   840     QWindowSurface *surface = qwidget->windowSurface();
       
   841     QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL;
       
   842 
       
   843     if (!engine)
       
   844         return;
       
   845 
       
   846     const bool sendNativePaintEvents = qwidget->d_func()->extraData()->receiveNativePaintEvents;
       
   847     if (sendNativePaintEvents) {
       
   848         const QRect r = qt_TRect2QRect(controlRect);
       
   849         QMetaObject::invokeMethod(qwidget, "beginNativePaintEvent", Qt::DirectConnection, Q_ARG(QRect, r));
       
   850     }
       
   851 
       
   852     // Map source rectangle into coordinates of the backing store.
       
   853     const QPoint controlBase(controlRect.iTl.iX, controlRect.iTl.iY);
       
   854     const QPoint backingStoreBase = qwidget->mapTo(qwidget->window(), controlBase);
       
   855     const TRect backingStoreRect(TPoint(backingStoreBase.x(), backingStoreBase.y()), controlRect.Size());
       
   856 
       
   857     if (engine->type() == QPaintEngine::Raster) {
       
   858         QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface());
       
   859         CFbsBitmap *bitmap = s60Surface->symbianBitmap();
       
   860         CWindowGc &gc = SystemGc();
       
   861 
       
   862         switch(qwidget->d_func()->extraData()->nativePaintMode) {
       
   863         case QWExtra::Disable:
       
   864             // Do nothing
       
   865             break;
       
   866 
       
   867         case QWExtra::Blit:
       
   868             if (qwidget->d_func()->isOpaque)
       
   869                 gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
       
   870             gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect);
       
   871             break;
       
   872 
       
   873         case QWExtra::ZeroFill:
       
   874             if (Window().DisplayMode() == EColor16MA) {
       
   875                 gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
       
   876                 gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
       
   877                 gc.SetBrushColor(TRgb::Color16MA(0));
       
   878                 gc.Clear(controlRect);
       
   879             } else {
       
   880                 gc.SetBrushColor(TRgb(0x000000));
       
   881                 gc.Clear(controlRect);
       
   882             };
       
   883             break;
       
   884 
       
   885         default:
       
   886             Q_ASSERT(false);
       
   887         }
       
   888     }
       
   889 
       
   890     if (sendNativePaintEvents) {
       
   891         const QRect r = qt_TRect2QRect(controlRect);
       
   892         // The draw ops aren't actually sent to WSERV until the graphics
       
   893         // context is deactivated, which happens in the function calling
       
   894         // this one.  We therefore delay the delivery of endNativePaintEvent,
       
   895         // to ensure that drawing has completed by the time the widget
       
   896         // receives the event.  Note that, if the widget needs to ensure
       
   897         // that the draw ops have actually been executed into the output
       
   898         // framebuffer, a call to RWsSession::Flush is required in the
       
   899         // endNativePaintEvent implementation.
       
   900         QMetaObject::invokeMethod(qwidget, "endNativePaintEvent", Qt::QueuedConnection, Q_ARG(QRect, r));
       
   901     }
       
   902 }
       
   903 
       
   904 void QSymbianControl::SizeChanged()
       
   905 {
       
   906     CCoeControl::SizeChanged();
       
   907 
       
   908     QSize oldSize = qwidget->size();
       
   909     QSize newSize(Size().iWidth, Size().iHeight);
       
   910 
       
   911     if (oldSize != newSize) {
       
   912         QRect cr = qwidget->geometry();
       
   913         cr.setSize(newSize);
       
   914         qwidget->data->crect = cr;
       
   915         if (qwidget->isVisible()) {
       
   916             QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData();
       
   917             bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
       
   918             if (!slowResize && tlwExtra)
       
   919                 tlwExtra->inTopLevelResize = true;
       
   920             QResizeEvent e(newSize, oldSize);
       
   921             qt_sendSpontaneousEvent(qwidget, &e);
       
   922             if (!qwidget->testAttribute(Qt::WA_StaticContents))
       
   923                 qwidget->d_func()->syncBackingStore();
       
   924             if (!slowResize && tlwExtra)
       
   925                 tlwExtra->inTopLevelResize = false;
       
   926         }
       
   927     }
       
   928 
       
   929     // CCoeControl::SetExtent calls SizeChanged, but does not call
       
   930     // PositionChanged, so we call it here to ensure that the widget's
       
   931     // position is updated.
       
   932     PositionChanged();
       
   933 }
       
   934 
       
   935 void QSymbianControl::PositionChanged()
       
   936 {
       
   937     CCoeControl::PositionChanged();
       
   938 
       
   939     QPoint oldPos = qwidget->geometry().topLeft();
       
   940     QPoint newPos(Position().iX, Position().iY);
       
   941 
       
   942     if (oldPos != newPos) {
       
   943         QRect cr = qwidget->geometry();
       
   944         cr.moveTopLeft(newPos);
       
   945         qwidget->data->crect = cr;
       
   946         QTLWExtra *top = qwidget->d_func()->maybeTopData();
       
   947         if (top && (qwidget->windowState() & (~Qt::WindowActive)) == Qt::WindowNoState)
       
   948             top->normalGeometry.moveTopLeft(newPos);
       
   949         if (qwidget->isVisible()) {
       
   950             QMoveEvent e(newPos, oldPos);
       
   951             qt_sendSpontaneousEvent(qwidget, &e);
       
   952         } else {
       
   953             QMoveEvent * e = new QMoveEvent(newPos, oldPos);
       
   954             QApplication::postEvent(qwidget, e);
       
   955         }
       
   956     }
       
   957 }
       
   958 
       
   959 void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
       
   960 {
       
   961     if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
       
   962         return;
       
   963 
       
   964     // Popups never get focused, but still receive the FocusChanged when they are hidden.
       
   965     if (QApplicationPrivate::popupWidgets != 0
       
   966             || (qwidget->windowType() & Qt::Popup) == Qt::Popup)
       
   967         return;
       
   968 
       
   969     if (IsFocused() && IsVisible()) {
       
   970         if (m_symbianPopupIsOpen) {
       
   971             QWidget *fw = QApplication::focusWidget();
       
   972             if (fw) {
       
   973                 QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
       
   974                 QCoreApplication::sendEvent(fw, &event);
       
   975             }
       
   976             m_symbianPopupIsOpen = false;
       
   977         }
       
   978 
       
   979         QApplication::setActiveWindow(qwidget->window());
       
   980         qwidget->d_func()->setWindowIcon_sys(true);
       
   981         qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
       
   982 #ifdef Q_WS_S60
       
   983         // If widget is fullscreen/minimized, hide status pane and button container otherwise show them.
       
   984         CEikStatusPane *statusPane = S60->statusPane();
       
   985         CEikButtonGroupContainer *buttonGroup = S60->buttonGroupContainer();
       
   986         TBool visible = !(qwidget->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized));
       
   987         if (statusPane)
       
   988             statusPane->MakeVisible(visible);
       
   989         if (buttonGroup) {
       
   990             // Visibility
       
   991             const TBool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
       
   992             const TBool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
       
   993             buttonGroup->MakeVisible(visible || (isFullscreen && cbaVisibilityHint));
       
   994 
       
   995             // Responsiviness
       
   996             CEikCba *cba = static_cast<CEikCba *>( buttonGroup->ButtonGroup() ); // downcast from MEikButtonGroup
       
   997             TUint cbaFlags = cba->ButtonGroupFlags();
       
   998             if(qwidget->windowFlags() & Qt::WindowSoftkeysRespondHint)
       
   999                 cbaFlags |= EAknCBAFlagRespondWhenInvisible;
       
  1000             else
       
  1001                 cbaFlags &= ~EAknCBAFlagRespondWhenInvisible;
       
  1002             cba->SetButtonGroupFlags(cbaFlags);
       
  1003         }
       
  1004 #endif
       
  1005     } else if (QApplication::activeWindow() == qwidget->window()) {
       
  1006         if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) {
       
  1007             QWidget *fw = QApplication::focusWidget();
       
  1008             if (fw) {
       
  1009                 QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
       
  1010                 QCoreApplication::sendEvent(fw, &event);
       
  1011             }
       
  1012             m_symbianPopupIsOpen = true;
       
  1013             return;
       
  1014         }
       
  1015 
       
  1016         QApplication::setActiveWindow(0);
       
  1017     }
       
  1018     // else { We don't touch the active window unless we were explicitly activated or deactivated }
       
  1019 }
       
  1020 
       
  1021 void QSymbianControl::handleClientAreaChange()
       
  1022 {
       
  1023     const bool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
       
  1024     if (qwidget->isFullScreen() && !cbaVisibilityHint) {
       
  1025         SetExtentToWholeScreen();
       
  1026     } else if (qwidget->isMaximized() || (qwidget->isFullScreen() && cbaVisibilityHint)) {
       
  1027         TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
       
  1028         SetExtent(r.iTl, r.Size());
       
  1029     } else if (!qwidget->isMinimized()) { // Normal geometry
       
  1030         if (!qwidget->testAttribute(Qt::WA_Resized)) {
       
  1031             qwidget->adjustSize();
       
  1032             qwidget->setAttribute(Qt::WA_Resized, false); //not a user resize
       
  1033         }
       
  1034         if (!qwidget->testAttribute(Qt::WA_Moved) && qwidget->windowType() != Qt::Dialog) {
       
  1035             TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
       
  1036             SetPosition(r.iTl);
       
  1037             qwidget->setAttribute(Qt::WA_Moved, false); // not really an explicit position
       
  1038         }
       
  1039     }
       
  1040 }
       
  1041 
       
  1042 void QSymbianControl::HandleResourceChange(int resourceType)
       
  1043 {
       
  1044     switch (resourceType) {
       
  1045     case KInternalStatusPaneChange:
       
  1046         handleClientAreaChange();
       
  1047         if (IsFocused() && IsVisible()) {
       
  1048             qwidget->d_func()->setWindowIcon_sys(true);
       
  1049             qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
       
  1050         }
       
  1051         break;
       
  1052     case KUidValueCoeFontChangeEvent:
       
  1053         // font change event
       
  1054         break;
       
  1055 #ifdef Q_WS_S60
       
  1056     case KEikDynamicLayoutVariantSwitch:
       
  1057     {
       
  1058         handleClientAreaChange();
       
  1059         break;
       
  1060     }
       
  1061 #endif
       
  1062     default:
       
  1063         break;
       
  1064     }
       
  1065 
       
  1066     CCoeControl::HandleResourceChange(resourceType);
       
  1067 
       
  1068 }
       
  1069 void QSymbianControl::CancelLongTapTimer()
       
  1070 {
       
  1071     m_longTapDetector->Cancel();
       
  1072 }
       
  1073 
       
  1074 TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id)
       
  1075 {
       
  1076     if (id.iUid == ETypeId)
       
  1077         return id.MakePtr(this);
       
  1078 
       
  1079     return CCoeControl::MopSupplyObject(id);
       
  1080 }
       
  1081 
       
  1082 void QSymbianControl::setFocusSafely(bool focus)
       
  1083 {
       
  1084     // The stack hack in here is very unfortunate, but it is the only way to ensure proper
       
  1085     // focus in Symbian. If this is not executed, the control which happens to be on
       
  1086     // the top of the stack may randomly be assigned focus by Symbian, for example
       
  1087     // when creating new windows (specifically in CCoeAppUi::HandleStackChanged()).
       
  1088     if (focus) {
       
  1089         S60->appUi()->RemoveFromStack(this);
       
  1090         // Symbian doesn't automatically remove focus from the last focused control, so we need to
       
  1091         // remember it and clear focus ourselves.
       
  1092         if (lastFocusedControl && lastFocusedControl != this)
       
  1093             lastFocusedControl->SetFocus(false);
       
  1094         QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
       
  1095                 ECoeStackPriorityDefault + 1, ECoeStackFlagStandard)); // Note the + 1
       
  1096         lastFocusedControl = this;
       
  1097         this->SetFocus(true);
       
  1098     } else {
       
  1099         S60->appUi()->RemoveFromStack(this);
       
  1100         QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
       
  1101                 ECoeStackPriorityDefault, ECoeStackFlagStandard));
       
  1102         if(this == lastFocusedControl)
       
  1103             lastFocusedControl = 0;
       
  1104         this->SetFocus(false);
       
  1105     }
       
  1106 }
       
  1107 
       
  1108 /*!
       
  1109     \typedef QApplication::QS60MainApplicationFactory
       
  1110     \since 4.6
       
  1111 
       
  1112     This is a typedef for a pointer to a function with the following
       
  1113     signature:
       
  1114 
       
  1115     \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 47
       
  1116 
       
  1117     \sa QApplication::QApplication()
       
  1118 */
       
  1119 
       
  1120 /*!
       
  1121     \since 4.6
       
  1122 
       
  1123     Creates an application using the application factory given in
       
  1124     \a factory, and using \a argc command line arguments in \a argv.
       
  1125     \a factory can be leaving, but the error will be converted to a
       
  1126     standard exception.
       
  1127 
       
  1128     This function is only available on S60.
       
  1129 */
       
  1130 QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv)
       
  1131     : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
       
  1132 {
       
  1133     Q_D(QApplication);
       
  1134     S60->s60ApplicationFactory = factory;
       
  1135     d->construct();
       
  1136 }
       
  1137 
       
  1138 QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int _internal)
       
  1139     : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
       
  1140 {
       
  1141     Q_D(QApplication);
       
  1142     S60->s60ApplicationFactory = factory;
       
  1143     d->construct();
       
  1144     QApplicationPrivate::app_compile_version = _internal;
       
  1145 }
       
  1146 
       
  1147 void qt_init(QApplicationPrivate * /* priv */, int)
       
  1148 {
       
  1149     if (!CCoeEnv::Static()) {
       
  1150         // The S60 framework creates a new trap handler which will render any existing traps
       
  1151         // invalid as long as it is active. This means that all code in main() that occurs after
       
  1152         // the QApplication construction needs to be surrounded by a new trap, despite having
       
  1153         // an outer one already. To avoid this, we save the original trap handler here, and set
       
  1154         // it back after the S60 framework is constructed. Then we restore it right before the S60
       
  1155         // framework destruction.
       
  1156         TTrapHandler *origTrapHandler = User::TrapHandler();
       
  1157 
       
  1158         // The S60 framework has not been initalized. We need to do it.
       
  1159         TApaApplicationFactory factory(S60->s60ApplicationFactory ?
       
  1160                 S60->s60ApplicationFactory : newS60Application);
       
  1161         CApaCommandLine* commandLine = 0;
       
  1162         TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
       
  1163         // After this construction, CEikonEnv will be available from CEikonEnv::Static().
       
  1164         // (much like our qApp).
       
  1165         CEikonEnv* coe = new CEikonEnv;
       
  1166         //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there.
       
  1167         if(err == KErrNone)
       
  1168             TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine));
       
  1169         delete commandLine;
       
  1170         if(err != KErrNone) {
       
  1171             qWarning() << "qt_init: Eikon application construct failed ("
       
  1172                        << err
       
  1173                        << "), maybe missing resource file on S60 3.1?";
       
  1174             delete coe;
       
  1175             qt_symbian_throwIfError(err);
       
  1176         }
       
  1177 
       
  1178         S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler);
       
  1179 
       
  1180         S60->qtOwnsS60Environment = true;
       
  1181     } else {
       
  1182         S60->qtOwnsS60Environment = false;
       
  1183     }
       
  1184 
       
  1185 #ifdef QT_NO_DEBUG
       
  1186     if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty())
       
  1187 #endif
       
  1188         S60->wsSession().SetAutoFlush(ETrue);
       
  1189 
       
  1190 #ifdef Q_SYMBIAN_WINDOW_SIZE_CACHE
       
  1191     TRAP_IGNORE(S60->wsSession().EnableWindowSizeCacheL());
       
  1192 #endif
       
  1193 
       
  1194     S60->updateScreenSize();
       
  1195 
       
  1196 
       
  1197     TDisplayMode mode = S60->screenDevice()->DisplayMode();
       
  1198     S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode);
       
  1199 
       
  1200     //NB: RWsSession::GetColorModeList tells you what window modes are supported,
       
  1201     //not what bitmap formats.
       
  1202     if(QSysInfo::symbianVersion() == QSysInfo::SV_9_2)
       
  1203         S60->supportsPremultipliedAlpha = 0;
       
  1204     else
       
  1205         S60->supportsPremultipliedAlpha = 1;
       
  1206 
       
  1207     RProcess me;
       
  1208     TSecureId securId = me.SecureId();
       
  1209     S60->uid = securId.operator TUid();
       
  1210 
       
  1211     // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app,
       
  1212     // and for dimming behind modal windows
       
  1213     S60->windowGroup().EnableFocusChangeEvents();
       
  1214 
       
  1215     //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this)
       
  1216     const TInt KMachineUidSamsungI8510 = 0x2000C51E;
       
  1217     // HAL::Get(HALData::EPen, TInt& result) may set 'result' to 1 on some 3.1 systems (e.g. N95).
       
  1218     // But we know that S60 systems below 5.0 did not support touch.
       
  1219     static const bool touchIsUnsupportedOnSystem =
       
  1220         QSysInfo::s60Version() == QSysInfo::SV_S60_3_1
       
  1221         || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2;
       
  1222     TInt machineUID;
       
  1223     TInt mouse;
       
  1224     TInt touch;
       
  1225     TInt err;
       
  1226     err = HAL::Get(HALData::EMouse, mouse);
       
  1227     if (err != KErrNone)
       
  1228         mouse = 0;
       
  1229     err = HAL::Get(HALData::EMachineUid, machineUID);
       
  1230     if (err != KErrNone)
       
  1231         machineUID = 0;
       
  1232     err = HAL::Get(HALData::EPen, touch);
       
  1233     if (err != KErrNone || touchIsUnsupportedOnSystem)
       
  1234         touch = 0;
       
  1235 #ifdef __WINS__
       
  1236     if(QSysInfo::symbianVersion() <= QSysInfo::SV_9_4) {
       
  1237         //for symbian SDK emulator, force values to match typical devices.
       
  1238         mouse = 0;
       
  1239         touch = touchIsUnsupportedOnSystem ? 0 : 1;
       
  1240     }
       
  1241 #endif
       
  1242     if (mouse || machineUID == KMachineUidSamsungI8510) {
       
  1243         S60->hasTouchscreen = false;
       
  1244         S60->virtualMouseRequired = false;
       
  1245     }
       
  1246     else if (!touch) {
       
  1247         S60->hasTouchscreen = false;
       
  1248         S60->virtualMouseRequired = true;
       
  1249     }
       
  1250     else {
       
  1251         S60->hasTouchscreen = true;
       
  1252         S60->virtualMouseRequired = false;
       
  1253     }
       
  1254 
       
  1255     S60->avkonComponentsSupportTransparency = false;
       
  1256     S60->menuBeingConstructed = false;
       
  1257 
       
  1258 #ifdef Q_WS_S60
       
  1259     TUid KCRUidAvkon = { 0x101F876E };
       
  1260     TUint32 KAknAvkonTransparencyEnabled = 0x0000000D;
       
  1261 
       
  1262     CRepository* repository = 0;
       
  1263     TRAP(err, repository = CRepository::NewL(KCRUidAvkon));
       
  1264 
       
  1265     if(err == KErrNone) {
       
  1266         TInt value = 0;
       
  1267         err = repository->Get(KAknAvkonTransparencyEnabled, value);
       
  1268         if(err == KErrNone) {
       
  1269             S60->avkonComponentsSupportTransparency = (value==1) ? true : false;
       
  1270         }
       
  1271     }
       
  1272 #endif
       
  1273 
       
  1274     if (touch) {
       
  1275         QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
       
  1276     } else {
       
  1277         QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional;
       
  1278     }
       
  1279 
       
  1280 #ifndef QT_NO_CURSOR
       
  1281     //Check if window server pointer cursors are supported or not
       
  1282 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
       
  1283     //In generic binary, use the HAL and OS version
       
  1284     //Any other known good phones should be added here.
       
  1285     if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4
       
  1286         && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion()
       
  1287         != QSysInfo::SV_9_2)) {
       
  1288         S60->brokenPointerCursors = false;
       
  1289         qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
       
  1290     }
       
  1291     else
       
  1292         S60->brokenPointerCursors = true;
       
  1293 #endif
       
  1294 
       
  1295     if (S60->mouseInteractionEnabled) {
       
  1296 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
       
  1297         if (S60->brokenPointerCursors) {
       
  1298             qt_symbian_set_pointer_sprite(Qt::ArrowCursor);
       
  1299             qt_symbian_show_pointer_sprite();
       
  1300         }
       
  1301         else
       
  1302 #endif
       
  1303             S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
       
  1304     }
       
  1305 #endif
       
  1306 
       
  1307     QFont systemFont;
       
  1308     systemFont.setFamily(systemFont.defaultFamily());
       
  1309     QApplicationPrivate::setSystemFont(systemFont);
       
  1310 
       
  1311 /*
       
  1312  ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
       
  1313     int argc = priv->argc;
       
  1314     char **argv = priv->argv;
       
  1315 
       
  1316     // Get command line params
       
  1317     int j = argc ? 1 : 0;
       
  1318     for (int i=1; i<argc; i++) {
       
  1319         if (argv[i] && *argv[i] != '-') {
       
  1320             argv[j++] = argv[i];
       
  1321             continue;
       
  1322         }
       
  1323 
       
  1324 #if defined(QT_DEBUG)
       
  1325         if (qstrcmp(argv[i], "-nograb") == 0)
       
  1326             appNoGrab = !appNoGrab;
       
  1327         else
       
  1328 #endif // QT_DEBUG
       
  1329             ;
       
  1330     }
       
  1331 */
       
  1332 
       
  1333     // Register WId with the metatype system.  This is to enable
       
  1334     // QWidgetPrivate::create_sys to used delayed slot invokation in order
       
  1335     // to destroy WId objects during reparenting.
       
  1336     qRegisterMetaType<WId>("WId");
       
  1337 }
       
  1338 
       
  1339 /*****************************************************************************
       
  1340   qt_cleanup() - cleans up when the application is finished
       
  1341  *****************************************************************************/
       
  1342 void qt_cleanup()
       
  1343 {
       
  1344     if(qt_S60Beep) {
       
  1345         delete qt_S60Beep;
       
  1346         qt_S60Beep = 0;
       
  1347     }
       
  1348     QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles
       
  1349 // S60 structure and window server session are freed in eventdispatcher destructor as they are needed there
       
  1350 
       
  1351     // It's important that this happens here, before the event dispatcher gets
       
  1352     // deleted, because the input context needs the event loop one last time before
       
  1353     // it dies.
       
  1354     delete QApplicationPrivate::inputContext;
       
  1355     QApplicationPrivate::inputContext = 0;
       
  1356 
       
  1357     //Change mouse pointer back
       
  1358     S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
       
  1359 
       
  1360     if (S60->qtOwnsS60Environment) {
       
  1361         // Restore the S60 framework trap handler. See qt_init().
       
  1362         User::SetTrapHandler(S60->s60InstalledTrapHandler);
       
  1363 
       
  1364         CEikonEnv* coe = CEikonEnv::Static();
       
  1365         coe->PrepareToExit();
       
  1366         // The CEikonEnv itself is destroyed in here.
       
  1367         coe->DestroyEnvironment();
       
  1368     }
       
  1369 }
       
  1370 
       
  1371 void QApplicationPrivate::initializeWidgetPaletteHash()
       
  1372 {
       
  1373     // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash()
       
  1374     // Possibly a task fot the S60Style guys
       
  1375 }
       
  1376 
       
  1377 void QApplicationPrivate::createEventDispatcher()
       
  1378 {
       
  1379     Q_Q(QApplication);
       
  1380     eventDispatcher = new QEventDispatcherS60(q);
       
  1381 }
       
  1382 
       
  1383 QString QApplicationPrivate::appName() const
       
  1384 {
       
  1385     return QCoreApplicationPrivate::appName();
       
  1386 }
       
  1387 
       
  1388 bool QApplicationPrivate::modalState()
       
  1389 {
       
  1390     return app_do_modal;
       
  1391 }
       
  1392 
       
  1393 void QApplicationPrivate::enterModal_sys(QWidget *widget)
       
  1394 {
       
  1395     if (widget) {
       
  1396         static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(ETrue);
       
  1397         // Modal partial screen dialogs (like queries) capture pointer events.
       
  1398         // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
       
  1399         widget->effectiveWinId()->SetGloballyCapturing(ETrue);
       
  1400         widget->effectiveWinId()->SetPointerCapture(ETrue);
       
  1401     }
       
  1402     if (!qt_modal_stack)
       
  1403         qt_modal_stack = new QWidgetList;
       
  1404     qt_modal_stack->insert(0, widget);
       
  1405     app_do_modal = true;
       
  1406 }
       
  1407 
       
  1408 void QApplicationPrivate::leaveModal_sys(QWidget *widget)
       
  1409 {
       
  1410     if (widget) {
       
  1411         static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(EFalse);
       
  1412         // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
       
  1413         widget->effectiveWinId()->SetGloballyCapturing(EFalse);
       
  1414         widget->effectiveWinId()->SetPointerCapture(EFalse);
       
  1415     }
       
  1416     if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
       
  1417         if (qt_modal_stack->isEmpty()) {
       
  1418             delete qt_modal_stack;
       
  1419             qt_modal_stack = 0;
       
  1420         }
       
  1421     }
       
  1422     app_do_modal = qt_modal_stack != 0;
       
  1423 }
       
  1424 
       
  1425 void QApplicationPrivate::openPopup(QWidget *popup)
       
  1426 {
       
  1427     if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
       
  1428         static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(ETrue);
       
  1429 
       
  1430     if (!QApplicationPrivate::popupWidgets)
       
  1431         QApplicationPrivate::popupWidgets = new QWidgetList;
       
  1432     QApplicationPrivate::popupWidgets->append(popup);
       
  1433 
       
  1434     // Cancel focus widget pointer capture and long tap timer
       
  1435     if (QApplication::focusWidget()) {
       
  1436         static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer();
       
  1437         QApplication::focusWidget()->effectiveWinId()->SetPointerCapture(false);
       
  1438         }
       
  1439 
       
  1440     if (!qt_nograb()) {
       
  1441         // Cancel pointer capture and long tap timer for earlier popup
       
  1442         int popupCount = QApplicationPrivate::popupWidgets->count();
       
  1443         if (popupCount > 1) {
       
  1444             QWidget* prevPopup = QApplicationPrivate::popupWidgets->at(popupCount-2);
       
  1445             static_cast<QSymbianControl*>(prevPopup->effectiveWinId())->CancelLongTapTimer();
       
  1446             prevPopup->effectiveWinId()->SetPointerCapture(false);
       
  1447         }
       
  1448 
       
  1449         // Enable pointer capture for this (topmost) popup
       
  1450         Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
       
  1451         WId id = popup->effectiveWinId();
       
  1452         id->SetPointerCapture(true);
       
  1453     }
       
  1454 
       
  1455     // popups are not focus-handled by the window system (the first
       
  1456     // popup grabbed the keyboard), so we have to do that manually: A
       
  1457     // new popup gets the focus
       
  1458     QWidget *fw = popup->focusWidget();
       
  1459     if (fw) {
       
  1460         fw->setFocus(Qt::PopupFocusReason);
       
  1461     } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
       
  1462         fw = QApplication::focusWidget();
       
  1463         if (fw) {
       
  1464             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
       
  1465             q_func()->sendEvent(fw, &e);
       
  1466         }
       
  1467     }
       
  1468 }
       
  1469 
       
  1470 void QApplicationPrivate::closePopup(QWidget *popup)
       
  1471 {
       
  1472     if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
       
  1473         static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(EFalse);
       
  1474 
       
  1475     if (!QApplicationPrivate::popupWidgets)
       
  1476         return;
       
  1477     QApplicationPrivate::popupWidgets->removeAll(popup);
       
  1478 
       
  1479     // Cancel pointer capture and long tap for this popup
       
  1480     WId id = popup->effectiveWinId();
       
  1481     id->SetPointerCapture(false);
       
  1482     static_cast<QSymbianControl*>(id)->CancelLongTapTimer();
       
  1483 
       
  1484     if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
       
  1485         delete QApplicationPrivate::popupWidgets;
       
  1486         QApplicationPrivate::popupWidgets = 0;
       
  1487         if (!qt_nograb()) {                        // grabbing not disabled
       
  1488             Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
       
  1489             if (QWidgetPrivate::mouseGrabber != 0)
       
  1490                 QWidgetPrivate::mouseGrabber->grabMouse();
       
  1491 
       
  1492             if (QWidgetPrivate::keyboardGrabber != 0)
       
  1493                 QWidgetPrivate::keyboardGrabber->grabKeyboard();
       
  1494 
       
  1495         QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
       
  1496               : q_func()->focusWidget();
       
  1497           if (fw) {
       
  1498               if(fw->window()->isModal()) // restore pointer capture for modal window
       
  1499                   fw->effectiveWinId()->SetPointerCapture(true);
       
  1500 
       
  1501               if (fw != q_func()->focusWidget()) {
       
  1502                   fw->setFocus(Qt::PopupFocusReason);
       
  1503               } else {
       
  1504                   QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
       
  1505                   q_func()->sendEvent(fw, &e);
       
  1506               }
       
  1507           }
       
  1508         }
       
  1509     } else {
       
  1510 
       
  1511         // popups are not focus-handled by the window system (the
       
  1512         // first popup grabbed the keyboard), so we have to do that
       
  1513         // manually: A popup was closed, so the previous popup gets
       
  1514         // the focus.
       
  1515         QWidget* aw = QApplicationPrivate::popupWidgets->last();
       
  1516         if (QWidget *fw = QApplication::focusWidget()) {
       
  1517             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
       
  1518             q_func()->sendEvent(fw, &e);
       
  1519         }
       
  1520 
       
  1521         // Enable pointer capture for previous popup
       
  1522         if (aw) {
       
  1523             aw->effectiveWinId()->SetPointerCapture(true);
       
  1524         }
       
  1525     }
       
  1526 }
       
  1527 
       
  1528 QWidget * QApplication::topLevelAt(QPoint const& point)
       
  1529 {
       
  1530     QWidget *found = 0;
       
  1531     int lowestZ = INT_MAX;
       
  1532     QWidgetList list = QApplication::topLevelWidgets();
       
  1533     for (int i = 0; i < list.count(); ++i) {
       
  1534         QWidget *widget = list.at(i);
       
  1535         if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
       
  1536             Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
       
  1537             if (widget->geometry().adjusted(0,0,1,1).contains(point)) {
       
  1538                 // At this point we know there is a Qt widget under the point.
       
  1539                 // Now we need to make sure it is the top most in the z-order.
       
  1540                 RDrawableWindow *const window = widget->effectiveWinId()->DrawableWindow();
       
  1541                 int z = window->OrdinalPosition();
       
  1542                 if (z < lowestZ) {
       
  1543                     lowestZ = z;
       
  1544                     found = widget;
       
  1545                 }
       
  1546             }
       
  1547         }
       
  1548     }
       
  1549     return found;
       
  1550 }
       
  1551 
       
  1552 void QApplication::alert(QWidget * /* widget */, int /* duration */)
       
  1553 {
       
  1554     // TODO: Implement QApplication::alert(QWidget *widget, int duration)
       
  1555 }
       
  1556 
       
  1557 int QApplication::doubleClickInterval()
       
  1558 {
       
  1559     TTimeIntervalMicroSeconds32 us;
       
  1560     TInt distance;
       
  1561     S60->wsSession().GetDoubleClickSettings(us, distance);
       
  1562     return (us.Int() / 1000);
       
  1563 }
       
  1564 
       
  1565 void QApplication::setDoubleClickInterval(int ms)
       
  1566 {
       
  1567     TTimeIntervalMicroSeconds32 newUs( ms * 1000);
       
  1568     TTimeIntervalMicroSeconds32 us;
       
  1569     TInt distance;
       
  1570     S60->wsSession().GetDoubleClickSettings(us, distance);
       
  1571     if (us != newUs)
       
  1572         S60->wsSession().SetDoubleClick(newUs, distance);
       
  1573 }
       
  1574 
       
  1575 int QApplication::keyboardInputInterval()
       
  1576 {
       
  1577     return QApplicationPrivate::keyboard_input_time;
       
  1578 }
       
  1579 
       
  1580 void QApplication::setKeyboardInputInterval(int ms)
       
  1581 {
       
  1582     QApplicationPrivate::keyboard_input_time = ms;
       
  1583 }
       
  1584 
       
  1585 int QApplication::cursorFlashTime()
       
  1586 {
       
  1587     return QApplicationPrivate::cursor_flash_time;
       
  1588 }
       
  1589 
       
  1590 void QApplication::setCursorFlashTime(int msecs)
       
  1591 {
       
  1592     QApplicationPrivate::cursor_flash_time = msecs;
       
  1593 }
       
  1594 
       
  1595 void QApplication::beep()
       
  1596 {
       
  1597     if (!qt_S60Beep) {
       
  1598         TInt frequency = 880;
       
  1599         TTimeIntervalMicroSeconds duration(500000);
       
  1600         TRAP_IGNORE(qt_S60Beep=QS60Beep::NewL(frequency, duration));
       
  1601     }
       
  1602     if (qt_S60Beep)
       
  1603         qt_S60Beep->Play();
       
  1604 }
       
  1605 
       
  1606 static inline bool callSymbianEventFilters(const QSymbianEvent *event)
       
  1607 {
       
  1608     long unused;
       
  1609     return qApp->filterEvent(const_cast<QSymbianEvent *>(event), &unused);
       
  1610 }
       
  1611 
       
  1612 /*!
       
  1613     \warning This function is only available on Symbian.
       
  1614     \since 4.6
       
  1615 
       
  1616     This function processes an individual Symbian event
       
  1617     \a event. It returns 1 if the event was handled, 0 if
       
  1618     the \a event was not handled, and -1 if the event was
       
  1619     not handled because the event is not known to Qt.
       
  1620  */
       
  1621 
       
  1622 int QApplication::symbianProcessEvent(const QSymbianEvent *event)
       
  1623 {
       
  1624     Q_D(QApplication);
       
  1625 
       
  1626     QScopedLoopLevelCounter counter(d->threadData);
       
  1627 
       
  1628     if (d->eventDispatcher->filterEvent(const_cast<QSymbianEvent *>(event)))
       
  1629         return 1;
       
  1630 
       
  1631     QWidget *w = qApp ? qApp->focusWidget() : 0;
       
  1632     if (w) {
       
  1633         QInputContext *ic = w->inputContext();
       
  1634         if (ic && ic->symbianFilterEvent(w, event))
       
  1635             return 1;
       
  1636     }
       
  1637 
       
  1638     if (symbianEventFilter(event))
       
  1639         return 1;
       
  1640 
       
  1641     switch (event->type()) {
       
  1642     case QSymbianEvent::WindowServerEvent:
       
  1643         return d->symbianProcessWsEvent(event);
       
  1644     case QSymbianEvent::CommandEvent:
       
  1645         return d->symbianHandleCommand(event);
       
  1646     case QSymbianEvent::ResourceChangeEvent:
       
  1647         return d->symbianResourceChange(event);
       
  1648     default:
       
  1649         return -1;
       
  1650     }
       
  1651 }
       
  1652 
       
  1653 int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent)
       
  1654 {
       
  1655     // Qt event handling. Handle some events regardless of if the handle is in our
       
  1656     // widget map or not.
       
  1657     const TWsEvent *event = symbianEvent->windowServerEvent();
       
  1658     CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle());
       
  1659     const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control);
       
  1660     switch (event->Type()) {
       
  1661     case EEventPointerEnter:
       
  1662         if (controlInMap) {
       
  1663             callSymbianEventFilters(symbianEvent);
       
  1664             return 1; // Qt::Enter will be generated in HandlePointerL
       
  1665         }
       
  1666         break;
       
  1667     case EEventPointerExit:
       
  1668         if (controlInMap) {
       
  1669             if (callSymbianEventFilters(symbianEvent))
       
  1670                 return 1;
       
  1671             if (S60) {
       
  1672                 // mouseEvent outside our window, send leave event to last focused widget
       
  1673                 QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos,
       
  1674                     Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier);
       
  1675                 if (S60->lastPointerEventTarget)
       
  1676                     qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent);
       
  1677                 S60->lastPointerEventTarget = 0;
       
  1678             }
       
  1679             return 1;
       
  1680         }
       
  1681         break;
       
  1682     case EEventScreenDeviceChanged:
       
  1683         if (callSymbianEventFilters(symbianEvent))
       
  1684             return 1;
       
  1685         if (S60)
       
  1686             S60->updateScreenSize();
       
  1687         if (qt_desktopWidget) {
       
  1688             QSize oldSize = qt_desktopWidget->size();
       
  1689             qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels);
       
  1690             qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels);
       
  1691             QResizeEvent e(qt_desktopWidget->size(), oldSize);
       
  1692             QApplication::sendEvent(qt_desktopWidget, &e);
       
  1693         }
       
  1694         return 0; // Propagate to CONE
       
  1695     case EEventWindowVisibilityChanged:
       
  1696         if (controlInMap) {
       
  1697             if (callSymbianEventFilters(symbianEvent))
       
  1698                 return 1;
       
  1699             const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
       
  1700             QWidget *w = QWidgetPrivate::mapper->value(control);
       
  1701             if (!w->d_func()->maybeTopData())
       
  1702                 break;
       
  1703             if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) {
       
  1704                 delete w->d_func()->topData()->backingStore;
       
  1705                 w->d_func()->topData()->backingStore = 0;
       
  1706                 // In order to ensure that any resources used by the window surface
       
  1707                 // are immediately freed, we flush the WSERV command buffer.
       
  1708                 S60->wsSession().Flush();
       
  1709             } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
       
  1710                        && !w->d_func()->maybeBackingStore()) {
       
  1711                 w->d_func()->topData()->backingStore = new QWidgetBackingStore(w);
       
  1712                 w->d_func()->invalidateBuffer(w->rect());
       
  1713                 w->repaint();
       
  1714             }
       
  1715             return 1;
       
  1716         }
       
  1717         break;
       
  1718     case EEventFocusGained:
       
  1719         if (callSymbianEventFilters(symbianEvent))
       
  1720             return 1;
       
  1721 #ifndef QT_NO_CURSOR
       
  1722         //re-enable mouse interaction
       
  1723         if (S60->mouseInteractionEnabled) {
       
  1724 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
       
  1725             if (S60->brokenPointerCursors)
       
  1726                 qt_symbian_show_pointer_sprite();
       
  1727             else
       
  1728 #endif
       
  1729                 S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
       
  1730         }
       
  1731 #endif
       
  1732         break;
       
  1733     case EEventFocusLost:
       
  1734         if (callSymbianEventFilters(symbianEvent))
       
  1735             return 1;
       
  1736 #ifndef QT_NO_CURSOR
       
  1737         //disable mouse as may be moving to application that does not support it
       
  1738         if (S60->mouseInteractionEnabled) {
       
  1739 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
       
  1740             if (S60->brokenPointerCursors)
       
  1741                 qt_symbian_hide_pointer_sprite();
       
  1742             else
       
  1743 #endif
       
  1744                 S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
       
  1745         }
       
  1746 #endif
       
  1747         break;
       
  1748     default:
       
  1749         break;
       
  1750     }
       
  1751 
       
  1752     if (!controlInMap)
       
  1753         return -1;
       
  1754 
       
  1755     return 0;
       
  1756 }
       
  1757 
       
  1758 /*!
       
  1759   \warning This virtual function is only available on Symbian.
       
  1760   \since 4.6
       
  1761 
       
  1762   If you create an application that inherits QApplication and reimplement
       
  1763   this function, you get direct access to events that the are received
       
  1764   from Symbian. The events are passed in the \a event parameter.
       
  1765 
       
  1766   Return true if you want to stop the event from being processed. Return
       
  1767   false for normal event dispatching. The default implementation returns
       
  1768   false, and does nothing with \a event.
       
  1769  */
       
  1770 bool QApplication::symbianEventFilter(const QSymbianEvent *event)
       
  1771 {
       
  1772     Q_UNUSED(event);
       
  1773     return false;
       
  1774 }
       
  1775 
       
  1776 /*!
       
  1777   \warning This function is only available on Symbian.
       
  1778   \since 4.6
       
  1779 
       
  1780   Handles \a{command}s which are typically handled by
       
  1781   CAknAppUi::HandleCommandL(). Qts Ui integration into Symbian is
       
  1782   partially achieved by deriving from CAknAppUi. Currently, exit,
       
  1783   menu and softkey commands are handled.
       
  1784 
       
  1785   \sa s60EventFilter(), s60ProcessEvent()
       
  1786 */
       
  1787 int QApplicationPrivate::symbianHandleCommand(const QSymbianEvent *symbianEvent)
       
  1788 {
       
  1789     Q_Q(QApplication);
       
  1790     int ret = 0;
       
  1791 
       
  1792     if (callSymbianEventFilters(symbianEvent))
       
  1793         return 1;
       
  1794 
       
  1795     int command = symbianEvent->command();
       
  1796 
       
  1797     switch (command) {
       
  1798 #ifdef Q_WS_S60
       
  1799     case EAknSoftkeyExit: {
       
  1800         QCloseEvent ev;
       
  1801         QApplication::sendSpontaneousEvent(q, &ev);
       
  1802         if (ev.isAccepted()) {
       
  1803             q->quit();
       
  1804             ret = 1;
       
  1805         }
       
  1806         break;
       
  1807     }
       
  1808 #endif
       
  1809     case EEikCmdExit:
       
  1810         q->quit();
       
  1811         ret = 1;
       
  1812         break;
       
  1813     default:
       
  1814         bool handled = QSoftKeyManager::handleCommand(command);
       
  1815         if (handled)
       
  1816             ret = 1;
       
  1817 #ifdef Q_WS_S60
       
  1818         else
       
  1819             ret = QMenuBarPrivate::symbianCommands(command);
       
  1820 #endif
       
  1821         break;
       
  1822     }
       
  1823 
       
  1824     return ret;
       
  1825 }
       
  1826 
       
  1827 /*!
       
  1828   \warning This function is only available on Symbian.
       
  1829   \since 4.6
       
  1830 
       
  1831   Handles the resource change specified by \a type.
       
  1832 
       
  1833   Currently, KEikDynamicLayoutVariantSwitch and
       
  1834   KAknsMessageSkinChange are handled.
       
  1835  */
       
  1836 int QApplicationPrivate::symbianResourceChange(const QSymbianEvent *symbianEvent)
       
  1837 {
       
  1838     int ret = 0;
       
  1839 
       
  1840     int type = symbianEvent->resourceChangeType();
       
  1841 
       
  1842     switch (type) {
       
  1843 #ifdef Q_WS_S60
       
  1844     case KEikDynamicLayoutVariantSwitch:
       
  1845         {
       
  1846         if (callSymbianEventFilters(symbianEvent))
       
  1847             return 1;
       
  1848         if (S60)
       
  1849             S60->updateScreenSize();
       
  1850 
       
  1851 #ifndef QT_NO_STYLE_S60
       
  1852         QS60Style *s60Style = 0;
       
  1853 
       
  1854 #ifndef QT_NO_STYLE_STYLESHEET
       
  1855         QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style());
       
  1856         if (proxy)
       
  1857             s60Style = qobject_cast<QS60Style*>(proxy->baseStyle());
       
  1858         else
       
  1859 #endif
       
  1860             s60Style = qobject_cast<QS60Style*>(QApplication::style());
       
  1861 
       
  1862         if (s60Style) {
       
  1863             s60Style->d_func()->handleDynamicLayoutVariantSwitch();
       
  1864             ret = 1;
       
  1865         }
       
  1866 #endif
       
  1867         }
       
  1868         break;
       
  1869 
       
  1870 #ifndef QT_NO_STYLE_S60
       
  1871     case KAknsMessageSkinChange:
       
  1872         if (callSymbianEventFilters(symbianEvent))
       
  1873             return 1;
       
  1874         if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) {
       
  1875             s60Style->d_func()->handleSkinChange();
       
  1876             ret = 1;
       
  1877         }
       
  1878         break;
       
  1879 #endif
       
  1880 #endif // Q_WS_S60
       
  1881     default:
       
  1882         break;
       
  1883     }
       
  1884 
       
  1885     return ret;
       
  1886 }
       
  1887 
       
  1888 #ifndef QT_NO_WHEELEVENT
       
  1889 int QApplication::wheelScrollLines()
       
  1890 {
       
  1891     return QApplicationPrivate::wheel_scroll_lines;
       
  1892 }
       
  1893 
       
  1894 void QApplication::setWheelScrollLines(int n)
       
  1895 {
       
  1896     QApplicationPrivate::wheel_scroll_lines = n;
       
  1897 }
       
  1898 #endif //QT_NO_WHEELEVENT
       
  1899 
       
  1900 bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */)
       
  1901 {
       
  1902     // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect)
       
  1903     return false;
       
  1904 }
       
  1905 
       
  1906 void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */)
       
  1907 {
       
  1908     // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
       
  1909 }
       
  1910 
       
  1911 TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym)
       
  1912 {
       
  1913     if (keysym) {
       
  1914         // If keysym is specified, cache it.
       
  1915         scanCodeCache.insert(scanCode, keysym);
       
  1916         return keysym;
       
  1917     } else {
       
  1918         // If not, retrieve the cached version.
       
  1919         return scanCodeCache[scanCode];
       
  1920     }
       
  1921 }
       
  1922 
       
  1923 void QApplicationPrivate::initializeMultitouch_sys()
       
  1924 {
       
  1925 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
       
  1926     if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone)
       
  1927         maxTouchPressure = KMaxTInt;
       
  1928 #endif
       
  1929 }
       
  1930 
       
  1931 void QApplicationPrivate::cleanupMultitouch_sys()
       
  1932 { }
       
  1933 
       
  1934 #ifndef QT_NO_SESSIONMANAGER
       
  1935 QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */)
       
  1936 {
       
  1937 
       
  1938 }
       
  1939 
       
  1940 QSessionManager::~QSessionManager()
       
  1941 {
       
  1942 
       
  1943 }
       
  1944 
       
  1945 bool QSessionManager::allowsInteraction()
       
  1946 {
       
  1947     return false;
       
  1948 }
       
  1949 
       
  1950 void QSessionManager::cancel()
       
  1951 {
       
  1952 
       
  1953 }
       
  1954 #endif //QT_NO_SESSIONMANAGER
       
  1955 
       
  1956 #ifdef QT_KEYPAD_NAVIGATION
       
  1957 /*
       
  1958  * Show/Hide the mouse cursor depending on phone type and chosen mode
       
  1959  */
       
  1960 void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode)
       
  1961 {
       
  1962 #ifndef QT_NO_CURSOR
       
  1963     const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto
       
  1964         && !S60->hasTouchscreen)
       
  1965         || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible;
       
  1966     const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto
       
  1967         && !S60->hasTouchscreen)
       
  1968         || mode == Qt::NavigationModeCursorForceVisible;
       
  1969 
       
  1970     if (!wasCursorOn && isCursorOn) {
       
  1971         //Show the cursor, when changing from another mode to cursor mode
       
  1972         qt_symbian_set_cursor_visible(true);
       
  1973     }
       
  1974     else if (wasCursorOn && !isCursorOn) {
       
  1975         //Hide the cursor, when leaving cursor mode
       
  1976         qt_symbian_set_cursor_visible(false);
       
  1977     }
       
  1978 #endif
       
  1979     QApplicationPrivate::navigationMode = mode;
       
  1980 }
       
  1981 #endif
       
  1982 
       
  1983 #ifndef QT_NO_CURSOR
       
  1984 /*****************************************************************************
       
  1985  QApplication cursor stack
       
  1986  *****************************************************************************/
       
  1987 
       
  1988 void QApplication::setOverrideCursor(const QCursor &cursor)
       
  1989 {
       
  1990     qApp->d_func()->cursor_list.prepend(cursor);
       
  1991     qt_symbian_setGlobalCursor(cursor);
       
  1992 }
       
  1993 
       
  1994 void QApplication::restoreOverrideCursor()
       
  1995 {
       
  1996     if (qApp->d_func()->cursor_list.isEmpty())
       
  1997         return;
       
  1998     qApp->d_func()->cursor_list.removeFirst();
       
  1999 
       
  2000     if (!qApp->d_func()->cursor_list.isEmpty()) {
       
  2001         qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first());
       
  2002     }
       
  2003     else {
       
  2004         //determine which widget has focus
       
  2005         QWidget *w = QApplication::widgetAt(QCursor::pos());
       
  2006 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
       
  2007         if (S60->brokenPointerCursors) {
       
  2008             qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor);
       
  2009         }
       
  2010         else
       
  2011 #endif
       
  2012         {
       
  2013             //because of the internals of window server, we need to force the cursor
       
  2014             //to be set in all child windows too, otherwise when the cursor is over
       
  2015             //the child window it may show a widget cursor or arrow cursor instead,
       
  2016             //depending on construction order.
       
  2017             QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys());
       
  2018             while (iter.hasNext()) {
       
  2019                 CCoeControl *ctrl = iter.next();
       
  2020                 if(ctrl->OwnsWindow()) {
       
  2021                     ctrl->DrawableWindow()->ClearPointerCursor();
       
  2022                 }
       
  2023             }
       
  2024             if (w)
       
  2025                 qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId());
       
  2026             else
       
  2027                 qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
       
  2028         }
       
  2029     }
       
  2030 }
       
  2031 
       
  2032 #endif // QT_NO_CURSOR
       
  2033 
       
  2034 QT_END_NAMESPACE