summaryrefslogtreecommitdiffstats
path: root/src/gui/platforms/s60/qapplication_s60.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/platforms/s60/qapplication_s60.cpp')
-rw-r--r--src/gui/platforms/s60/qapplication_s60.cpp2712
1 files changed, 2712 insertions, 0 deletions
diff --git a/src/gui/platforms/s60/qapplication_s60.cpp b/src/gui/platforms/s60/qapplication_s60.cpp
new file mode 100644
index 0000000000..408c3b5883
--- /dev/null
+++ b/src/gui/platforms/s60/qapplication_s60.cpp
@@ -0,0 +1,2712 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication_p.h"
+#include "qsessionmanager.h"
+#include "qevent.h"
+#include "qsymbianevent.h"
+#include "qeventdispatcher_s60_p.h"
+#include "qwidget.h"
+#include "qdesktopwidget.h"
+#include "private/qbackingstore_p.h"
+#include "qt_s60_p.h"
+#include "private/qevent_p.h"
+#include "qstring.h"
+#include "qdebug.h"
+#include "qimage.h"
+#include "qcombobox.h"
+#include "private/qkeymapper_p.h"
+#include "private/qfont_p.h"
+#ifndef QT_NO_STYLE_S60
+#include "private/qs60style_p.h"
+#endif
+#include "private/qwindowsurface_s60_p.h"
+#include "qpaintengine.h"
+#include "private/qmenubar_p.h"
+#include "private/qsoftkeymanager_p.h"
+#ifdef QT_GRAPHICSSYSTEM_RUNTIME
+#include "private/qgraphicssystem_runtime_p.h"
+#endif
+
+#include "apgwgnam.h" // For CApaWindowGroupName
+#include <mdaaudiotoneplayer.h> // For CMdaAudioToneUtility
+
+#if defined(Q_OS_SYMBIAN)
+# include <private/qs60mainapplication_p.h>
+# include <centralrepository.h>
+# include "qs60mainappui.h"
+# include "qinputcontext.h"
+#endif
+
+#if defined(Q_WS_S60)
+# if !defined(QT_NO_IM)
+# include <private/qcoefepinputcontext_p.h>
+# endif
+#endif
+
+#include "private/qstylesheetstyle_p.h"
+
+#include <hal.h>
+#include <hal_data.h>
+
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
+#include <graphics/wstfxconst.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// Goom Events through Window Server
+static const int KGoomMemoryLowEvent = 0x10282DBF;
+static const int KGoomMemoryGoodEvent = 0x20026790;
+// Split view open/close events from AVKON
+static const int KSplitViewOpenEvent = 0x2001E2C0;
+static const int KSplitViewCloseEvent = 0x2001E2C1;
+
+#if defined(QT_DEBUG)
+static bool appNoGrab = false; // Grabbing enabled
+#endif
+static bool app_do_modal = false; // modal mode
+Q_GLOBAL_STATIC(QS60Data, qt_s60Data);
+
+extern bool qt_sendSpontaneousEvent(QObject*,QEvent*);
+extern QWidgetList *qt_modal_stack; // stack of modal widgets
+extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
+
+QWidget *qt_button_down = 0; // widget got last button-down
+
+QSymbianControl *QSymbianControl::lastFocusedControl = 0;
+
+QS60Data* qGlobalS60Data()
+{
+ return qt_s60Data();
+}
+
+#ifdef Q_WS_S60
+void QS60Data::setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, bool buttonGroupVisible)
+{
+ bool buttonGroupVisibilityChanged = false;
+ if (CEikButtonGroupContainer *const b = buttonGroupContainer()) {
+ buttonGroupVisibilityChanged = (b->IsVisible() != buttonGroupVisible);
+ b->MakeVisible(buttonGroupVisible);
+ }
+ bool statusPaneVisibilityChanged = false;
+ if (CEikStatusPane *const s = statusPane()) {
+ statusPaneVisibilityChanged = (s->IsVisible() != statusPaneVisible);
+ s->MakeVisible(statusPaneVisible);
+ }
+ if (buttonGroupVisibilityChanged || statusPaneVisibilityChanged) {
+ const QSize size = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect()).size();
+ const QSize oldSize; // note that QDesktopWidget::resizeEvent ignores the QResizeEvent contents
+ QResizeEvent event(size, oldSize);
+ QApplication::instance()->sendEvent(QApplication::desktop(), &event);
+ }
+ if (buttonGroupVisibilityChanged && !statusPaneVisibilityChanged && QApplication::activeWindow())
+ // Ensure that control rectangle is updated
+ static_cast<QSymbianControl *>(QApplication::activeWindow()->winId())->handleClientAreaChange();
+}
+
+bool QS60Data::setRecursiveDecorationsVisibility(QWidget *window, Qt::WindowStates newState)
+{
+ // Show statusbar:
+ // Topmost parent: Show unless fullscreen/minimized.
+ // Child windows: Follow topmost parent, unless fullscreen, in which case do not show statusbar
+ // Show CBA:
+ // Topmost parent: Show unless fullscreen/minimized.
+ // Exception: Show if fullscreen with Qt::WindowSoftkeysVisibleHint.
+ // Child windows:
+ // Minimized: Unclear if there is an use case for having focused minimized window at all.
+ // Always follow topmost parent just to be safe.
+ // Maximized and normal: follow topmost parent.
+ // Exception: If topmost parent is not showing CBA, show CBA if any softkey actions are
+ // defined.
+ // Fullscreen: Show only if Qt::WindowSoftkeysVisibleHint set.
+
+ Qt::WindowStates comparisonState = newState;
+ QWidget *parentWindow = window->parentWidget();
+ if (parentWindow) {
+ while (parentWindow->parentWidget())
+ parentWindow = parentWindow->parentWidget();
+ comparisonState = parentWindow->windowState();
+ } else {
+ parentWindow = window;
+ }
+
+ bool decorationsVisible = !(comparisonState & (Qt::WindowFullScreen | Qt::WindowMinimized));
+ const bool parentIsFullscreen = comparisonState & Qt::WindowFullScreen;
+ const bool parentCbaVisibilityHint = parentWindow->windowFlags() & Qt::WindowSoftkeysVisibleHint;
+ bool buttonGroupVisibility = (decorationsVisible || (parentIsFullscreen && parentCbaVisibilityHint));
+
+ // Do extra checking for child windows
+ if (window->parentWidget()) {
+ if (newState & Qt::WindowFullScreen) {
+ decorationsVisible = false;
+ if (window->windowFlags() & Qt::WindowSoftkeysVisibleHint)
+ buttonGroupVisibility = true;
+ else
+ buttonGroupVisibility = false;
+ } else if (!(newState & Qt::WindowMinimized) && !buttonGroupVisibility) {
+ for (int i = 0; i < window->actions().size(); ++i) {
+ if (window->actions().at(i)->softKeyRole() != QAction::NoSoftKey) {
+ buttonGroupVisibility = true;
+ break;
+ }
+ }
+ }
+ }
+
+ S60->setStatusPaneAndButtonGroupVisibility(decorationsVisible, buttonGroupVisibility);
+
+ return decorationsVisible;
+}
+#endif
+
+void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible)
+{
+ if (QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control)) {
+ QWidget *const widget = QWidgetPrivate::mapper->value(control);
+ QWidget *const window = widget->window();
+ if (QTLWExtra *topData = qt_widget_private(window)->maybeTopData()) {
+ QWidgetBackingStoreTracker &backingStore = topData->backingStore;
+ if (visible) {
+ if (backingStore.data()) {
+ backingStore.registerWidget(widget);
+ } else {
+ backingStore.create(window);
+ backingStore.registerWidget(widget);
+ qt_widget_private(widget)->invalidateBuffer(widget->rect());
+ widget->repaint();
+ }
+ } else {
+ // In certain special scenarios we may get an ENotVisible event
+ // without a previous EPartiallyVisible. The backingstore must
+ // still be destroyed, hence the registerWidget() call below.
+ if (backingStore.data() && widget->internalWinId()
+ && qt_widget_private(widget)->maybeBackingStore() == backingStore.data())
+ backingStore.registerWidget(widget);
+ backingStore.unregisterWidget(widget);
+ // In order to ensure that any resources used by the window surface
+ // are immediately freed, we flush the WSERV command buffer.
+ S60->wsSession().Flush();
+ }
+ }
+ }
+}
+
+bool qt_nograb() // application no-grab option
+{
+#if defined(QT_DEBUG)
+ return appNoGrab;
+#else
+ return false;
+#endif
+}
+
+// Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument
+class QS60Beep : public CBase, public MMdaAudioToneObserver
+{
+public:
+ static QS60Beep* NewL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration);
+ void Play();
+ ~QS60Beep();
+private:
+ void ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration);
+ void MatoPrepareComplete(TInt aError);
+ void MatoPlayComplete(TInt aError);
+private:
+ typedef enum
+ {
+ EBeepNotPrepared,
+ EBeepPrepared,
+ EBeepPlaying
+ } TBeepState;
+private:
+ CMdaAudioToneUtility* iToneUtil;
+ TBeepState iState;
+ TInt iFrequency;
+ TTimeIntervalMicroSeconds iDuration;
+};
+
+static QS60Beep* qt_S60Beep = 0;
+
+QS60Beep::~QS60Beep()
+{
+ if (iToneUtil) {
+ switch (iState) {
+ case EBeepPlaying:
+ iToneUtil->CancelPlay();
+ break;
+ case EBeepNotPrepared:
+ iToneUtil->CancelPrepare();
+ break;
+ }
+ }
+ delete iToneUtil;
+}
+
+QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
+{
+ QS60Beep* self = new (ELeave) QS60Beep();
+ CleanupStack::PushL(self);
+ self->ConstructL(aFrequency, aDuration);
+ CleanupStack::Pop();
+ return self;
+}
+
+void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
+{
+ iToneUtil = CMdaAudioToneUtility::NewL(*this);
+ iState = EBeepNotPrepared;
+ iFrequency = aFrequency;
+ iDuration = aDuration;
+ iToneUtil->PrepareToPlayTone(iFrequency, iDuration);
+}
+
+void QS60Beep::Play()
+{
+ if (iState == EBeepPlaying) {
+ iToneUtil->CancelPlay();
+ iState = EBeepPrepared;
+ }
+
+ iToneUtil->Play();
+ iState = EBeepPlaying;
+}
+
+void QS60Beep::MatoPrepareComplete(TInt aError)
+{
+ if (aError == KErrNone) {
+ iState = EBeepPrepared;
+ Play();
+ }
+}
+
+void QS60Beep::MatoPlayComplete(TInt aError)
+{
+ Q_UNUSED(aError);
+ iState = EBeepPrepared;
+}
+
+
+static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers)
+{
+ Qt::KeyboardModifiers result = Qt::NoModifier;
+
+ if (s60Modifiers & EModifierKeypad)
+ result |= Qt::KeypadModifier;
+ if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift
+ || s60Modifiers & EModifierRightShift)
+ result |= Qt::ShiftModifier;
+ if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl
+ || s60Modifiers & EModifierRightCtrl)
+ result |= Qt::ControlModifier;
+ if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt
+ || s60Modifiers & EModifierRightAlt)
+ result |= Qt::AltModifier;
+
+ return result;
+}
+
+static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent)
+{
+ switch (pEvent->iType) {
+ case TPointerEvent::EButton1Down:
+ *type = QEvent::MouseButtonPress;
+ *button = Qt::LeftButton;
+ break;
+ case TPointerEvent::EButton1Up:
+ *type = QEvent::MouseButtonRelease;
+ *button = Qt::LeftButton;
+ break;
+ case TPointerEvent::EButton2Down:
+ *type = QEvent::MouseButtonPress;
+ *button = Qt::MidButton;
+ break;
+ case TPointerEvent::EButton2Up:
+ *type = QEvent::MouseButtonRelease;
+ *button = Qt::MidButton;
+ break;
+ case TPointerEvent::EButton3Down:
+ *type = QEvent::MouseButtonPress;
+ *button = Qt::RightButton;
+ break;
+ case TPointerEvent::EButton3Up:
+ *type = QEvent::MouseButtonRelease;
+ *button = Qt::RightButton;
+ break;
+ case TPointerEvent::EDrag:
+ *type = QEvent::MouseMove;
+ *button = Qt::NoButton;
+ break;
+ case TPointerEvent::EMove:
+ // Qt makes no distinction between move and drag
+ *type = QEvent::MouseMove;
+ *button = Qt::NoButton;
+ break;
+ default:
+ *type = QEvent::None;
+ *button = Qt::NoButton;
+ break;
+ }
+ if (pEvent->iModifiers & EModifierDoubleClick){
+ *type = QEvent::MouseButtonDblClick;
+ }
+
+ if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick)
+ QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button);
+ else if (*type == QEvent::MouseButtonRelease)
+ QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button));
+
+ QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask;
+}
+
+//### Can be replaced with CAknLongTapDetector if animation is required.
+//NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,.
+//also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used.
+class QLongTapTimer : public CTimer
+{
+public:
+ static QLongTapTimer* NewL(QAbstractLongTapObserver *observer);
+ QLongTapTimer(QAbstractLongTapObserver *observer);
+ void ConstructL();
+public:
+ void PointerEventL(const TPointerEvent &event);
+ void RunL();
+protected:
+private:
+ QAbstractLongTapObserver *m_observer;
+ TPointerEvent m_event;
+ QPoint m_pressedCoordinates;
+ int m_dragDistance;
+};
+
+QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer)
+{
+ QLongTapTimer* self = new QLongTapTimer(observer);
+ self->ConstructL();
+ return self;
+}
+void QLongTapTimer::ConstructL()
+{
+ CTimer::ConstructL();
+}
+
+QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh)
+{
+ m_observer = observer;
+ m_dragDistance = qApp->startDragDistance();
+ CActiveScheduler::Add(this);
+}
+
+void QLongTapTimer::PointerEventL(const TPointerEvent& event)
+{
+ if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat)
+ {
+ QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates);
+ if (diff.manhattanLength() < m_dragDistance)
+ return;
+ }
+ Cancel();
+ m_event = event;
+ if (event.iType == TPointerEvent::EButton1Down)
+ {
+ m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY);
+ // must be same as KLongTapDelay in aknlongtapdetector.h
+ After(800000);
+ }
+}
+void QLongTapTimer::RunL()
+{
+ if (m_observer)
+ m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition);
+}
+
+QSymbianControl::QSymbianControl(QWidget *w)
+ : CCoeControl()
+ , qwidget(w)
+ , m_longTapDetector(0)
+ , m_ignoreFocusChanged(0)
+ , m_symbianPopupIsOpen(0)
+ , m_inExternalScreenOverride(false)
+ , m_lastStatusPaneVisibility(0)
+{
+}
+
+void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
+{
+ if (!desktop)
+ {
+ if (isWindowOwning || !qwidget->parentWidget()
+ || qwidget->parentWidget()->windowType() == Qt::Desktop) {
+ RWindowGroup &wg(S60->windowGroup(qwidget));
+ CreateWindowL(wg);
+ } else {
+ /**
+ * TODO: in order to avoid creating windows for all ancestors of
+ * this widget up to the root window, the parameter passed to
+ * CreateWindowL should be
+ * qwidget->parentWidget()->effectiveWinId(). However, if we do
+ * this, then we need to take care of re-parenting when a window
+ * is created for a widget between this one and the root window.
+ */
+ CreateWindowL(qwidget->parentWidget()->winId());
+ }
+
+ // Necessary in order to be able to track the activation status of
+ // the control's window
+ qwidget->d_func()->createExtra();
+
+ SetFocusing(true);
+ m_longTapDetector = QLongTapTimer::NewL(this);
+ m_doubleClickTimer.invalidate();
+
+ DrawableWindow()->SetPointerGrab(ETrue);
+ }
+
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
+ if (OwnsWindow()) {
+ TTfxWindowPurpose windowPurpose(ETfxPurposeNone);
+ switch (qwidget->windowType()) {
+ case Qt::Dialog:
+ windowPurpose = ETfxPurposeDialogWindow;
+ break;
+ case Qt::Popup:
+ windowPurpose = ETfxPurposePopupWindow;
+ break;
+ case Qt::Tool:
+ windowPurpose = ETfxPurposeToolWindow;
+ break;
+ case Qt::ToolTip:
+ windowPurpose = ETfxPurposeToolTipWindow;
+ break;
+ case Qt::SplashScreen:
+ windowPurpose = ETfxPurposeSplashScreenWindow;
+ break;
+ default:
+ windowPurpose = (isWindowOwning || !qwidget->parentWidget() || qwidget->parentWidget()->windowType() == Qt::Desktop)
+ ? ETfxPurposeWindow : ETfxPurposeChildWindow;
+ break;
+ }
+ Window().SetPurpose(windowPurpose);
+ }
+#endif
+}
+
+QSymbianControl::~QSymbianControl()
+{
+ // Ensure backing store is deleted before the top-level
+ // window is destroyed
+ qt_widget_private(qwidget)->topData()->backingStore.destroy();
+
+ if (S60->curWin == this)
+ S60->curWin = 0;
+ if (!QApplicationPrivate::is_app_closing) {
+ QT_TRY {
+ setFocusSafely(false);
+ } QT_CATCH(const std::exception&) {
+ // ignore exceptions, nothing can be done
+ }
+ }
+ S60->appUi()->RemoveFromStack(this);
+ delete m_longTapDetector;
+}
+
+void QSymbianControl::setWidget(QWidget *w)
+{
+ qwidget = w;
+}
+
+QPoint QSymbianControl::translatePointForFixedNativeOrientation(const TPoint &pointerEventPos) const
+{
+ QPoint pos(pointerEventPos.iX, pointerEventPos.iY);
+ if (qwidget->d_func()->fixNativeOrientationCalled) {
+ QSize wsize = qwidget->size();
+ TSize size = Size();
+ if (size.iWidth == wsize.height() && size.iHeight == wsize.width()) {
+ qreal x = pos.x();
+ qreal y = pos.y();
+ pos.setX(size.iHeight - y);
+ pos.setY(x);
+ }
+ }
+ return pos;
+}
+
+TRect QSymbianControl::translateRectForFixedNativeOrientation(const TRect &controlRect) const
+{
+ TRect rect = controlRect;
+ if (qwidget->d_func()->fixNativeOrientationCalled) {
+ QPoint a = translatePointForFixedNativeOrientation(rect.iTl);
+ QPoint b = translatePointForFixedNativeOrientation(rect.iBr);
+ if (a.x() < b.x()) {
+ rect.iTl.iX = a.x();
+ rect.iBr.iX = b.x();
+ } else {
+ rect.iTl.iX = b.x();
+ rect.iBr.iX = a.x();
+ }
+ if (a.y() < b.y()) {
+ rect.iTl.iY = a.y();
+ rect.iBr.iY = b.y();
+ } else {
+ rect.iTl.iY = b.y();
+ rect.iBr.iY = a.y();
+ }
+ }
+ return rect;
+}
+
+void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation )
+{
+ QWidget *alienWidget;
+ QPoint widgetPos = translatePointForFixedNativeOrientation(aPenEventLocation);
+ QPoint globalPos = translatePointForFixedNativeOrientation(aPenEventScreenLocation);
+ alienWidget = qwidget->childAt(widgetPos);
+ if (!alienWidget)
+ alienWidget = qwidget;
+
+#if !defined(QT_NO_CONTEXTMENU)
+ QContextMenuEvent contextMenuEvent(QContextMenuEvent::Mouse, widgetPos, globalPos, Qt::NoModifier);
+ qt_sendSpontaneousEvent(alienWidget, &contextMenuEvent);
+#endif
+}
+
+#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event)
+{
+ QApplicationPrivate *d = QApplicationPrivate::instance();
+ QPointF screenPos = qwidget->mapToGlobal(translatePointForFixedNativeOrientation(event->iPosition));
+ qreal pressure;
+ if(d->pressureSupported
+ && event->Pressure() > 0) //workaround for misconfigured HAL
+ pressure = event->Pressure() / qreal(d->maxTouchPressure);
+ else
+ pressure = qreal(1.0);
+ processTouchEvent(event->PointerNumber(), event->iType, screenPos, pressure);
+}
+#endif
+
+void QSymbianControl::processTouchEvent(int pointerNumber, TPointerEvent::TType type, QPointF screenPos, qreal pressure)
+{
+ QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget);
+
+ QApplicationPrivate *d = QApplicationPrivate::instance();
+
+ QList<QTouchEvent::TouchPoint> points = d->appAllTouchPoints;
+ while (points.count() <= pointerNumber)
+ points.append(QTouchEvent::TouchPoint(points.count()));
+
+ Qt::TouchPointStates allStates = 0;
+ for (int i = 0; i < points.count(); ++i) {
+ QTouchEvent::TouchPoint &touchPoint = points[i];
+
+ if (touchPoint.id() == pointerNumber) {
+ Qt::TouchPointStates state;
+ switch (type) {
+ case TPointerEvent::EButton1Down:
+#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+ case TPointerEvent::EEnterHighPressure:
+#endif
+ state = Qt::TouchPointPressed;
+ break;
+ case TPointerEvent::EButton1Up:
+#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+ case TPointerEvent::EExitCloseProximity:
+#endif
+ state = Qt::TouchPointReleased;
+ break;
+ case TPointerEvent::EDrag:
+ state = Qt::TouchPointMoved;
+ break;
+ default:
+ // how likely is this to happen?
+ state = Qt::TouchPointStationary;
+ break;
+ }
+ if (pointerNumber == 0)
+ state |= Qt::TouchPointPrimary;
+ touchPoint.setState(state);
+
+ touchPoint.setScreenPos(screenPos);
+ touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(),
+ screenPos.y() / screenGeometry.height()));
+
+ touchPoint.setPressure(pressure);
+ } else if (touchPoint.state() != Qt::TouchPointReleased) {
+ // all other active touch points should be marked as stationary
+ touchPoint.setState(Qt::TouchPointStationary);
+ }
+
+ allStates |= touchPoint.state();
+ }
+
+ if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) {
+ // all touch points released
+ d->appAllTouchPoints.clear();
+ } else {
+ d->appAllTouchPoints = points;
+ }
+
+ QApplicationPrivate::translateRawTouchEvent(qwidget,
+ QTouchEvent::TouchScreen,
+ points);
+}
+
+void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent)
+{
+#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+ if (pEvent.IsAdvancedPointerEvent()) {
+ const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent();
+ translateAdvancedPointerEvent(advancedPointerEvent);
+ if (advancedPointerEvent->PointerNumber() != 0) {
+ // only send mouse events for the first touch point
+ return;
+ }
+ }
+#endif
+
+ m_longTapDetector->PointerEventL(pEvent);
+ QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent));
+}
+
+void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
+{
+ QMouseEvent::Type type;
+ Qt::MouseButton button;
+ mapS60MouseEventTypeToQt(&type, &button, &pEvent);
+ Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers);
+
+ QPoint widgetPos = translatePointForFixedNativeOrientation(pEvent.iPosition);
+ TPoint controlScreenPos = PositionRelativeToScreen();
+ QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;
+ S60->lastCursorPos = globalPos;
+ S60->lastPointerEventPos = widgetPos;
+
+ QWidget *mouseGrabber = QWidget::mouseGrabber();
+
+ QWidget *popupWidget = qApp->activePopupWidget();
+ QWidget *popupReceiver = 0;
+ if (popupWidget) {
+ QWidget *popupChild = popupWidget->childAt(popupWidget->mapFromGlobal(globalPos));
+ popupReceiver = popupChild ? popupChild : popupWidget;
+ }
+
+ if (mouseGrabber) {
+ if (popupReceiver) {
+ sendMouseEvent(popupReceiver, type, globalPos, button, modifiers);
+ } else {
+ sendMouseEvent(mouseGrabber, type, globalPos, button, modifiers);
+ }
+ // No Enter/Leave events in grabbing mode.
+ return;
+ }
+
+ QWidget *widgetUnderPointer = qwidget->childAt(widgetPos);
+ if (!widgetUnderPointer)
+ widgetUnderPointer = qwidget;
+
+ QApplicationPrivate::dispatchEnterLeave(widgetUnderPointer, S60->lastPointerEventTarget);
+ S60->lastPointerEventTarget = widgetUnderPointer;
+
+ QWidget *receiver;
+ if (!popupReceiver && S60->mousePressTarget && type != QEvent::MouseButtonPress) {
+ receiver = S60->mousePressTarget;
+ if (type == QEvent::MouseButtonRelease)
+ S60->mousePressTarget = 0;
+ } else {
+ receiver = popupReceiver ? popupReceiver : widgetUnderPointer;
+ if (type == QEvent::MouseButtonPress)
+ S60->mousePressTarget = receiver;
+ }
+
+#if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS)
+ if (S60->brokenPointerCursors)
+ qt_symbian_move_cursor_sprite();
+#endif
+
+//Generate single touch event for S60 5.0 (has touchscreen, does not have advanced pointers)
+#ifndef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+ if (S60->hasTouchscreen) {
+ processTouchEvent(0, pEvent.iType, QPointF(globalPos), 1.0);
+ }
+#endif
+
+ sendMouseEvent(receiver, type, globalPos, button, modifiers);
+}
+
+#ifdef Q_WS_S60
+void QSymbianControl::HandleStatusPaneSizeChange()
+{
+ QS60MainAppUi *s60AppUi = static_cast<QS60MainAppUi *>(S60->appUi());
+ s60AppUi->HandleStatusPaneSizeChange();
+}
+#endif
+
+void QSymbianControl::sendMouseEvent(
+ QWidget *receiver,
+ QEvent::Type type,
+ const QPoint &globalPos,
+ Qt::MouseButton button,
+ Qt::KeyboardModifiers modifiers)
+{
+ Q_ASSERT(receiver);
+ QMouseEvent mEvent(type, receiver->mapFromGlobal(globalPos), globalPos,
+ button, QApplicationPrivate::mouse_buttons, modifiers);
+ QEventDispatcherS60 *dispatcher;
+ // It is theoretically possible for someone to install a different event dispatcher.
+ if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(receiver->d_func()->threadData->eventDispatcher)) != 0) {
+ if (dispatcher->excludeUserInputEvents()) {
+ dispatcher->saveInputEvent(this, receiver, new QMouseEvent(mEvent));
+ return;
+ }
+ }
+
+ sendMouseEvent(receiver, &mEvent);
+}
+
+bool QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent)
+{
+ return qt_sendSpontaneousEvent(widget, mEvent);
+}
+
+TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type)
+{
+ TKeyResponse r = EKeyWasNotConsumed;
+ QT_TRYCATCH_LEAVING(r = OfferKeyEvent(keyEvent, type));
+ return r;
+}
+
+TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type)
+{
+ /*
+ S60 has a confusing way of delivering key events. There are three types of
+ events: EEventKey, EEventKeyDown and EEventKeyUp. When a key is pressed,
+ EEventKeyDown is first generated, followed by EEventKey. Then, when the key is
+ released, EEventKeyUp is generated.
+ However, it is possible that only the EEventKey is generated alone, typically
+ in relation to virtual keyboards. In that case we need to take care to
+ generate both press and release events in Qt, since applications expect that.
+ We do this by having three states for each used scan code, depending on the
+ events received. See the switch below for what happens in each state
+ transition.
+ */
+
+ if (type != EEventKeyDown)
+ if (handleVirtualMouse(keyEvent, type) == EKeyWasConsumed)
+ return EKeyWasConsumed;
+
+ TKeyResponse ret = EKeyWasNotConsumed;
+#define GET_RETURN(x) (ret = ((x) == EKeyWasConsumed) ? EKeyWasConsumed : ret)
+
+ // This top level switch corresponds to the states, and the inner switches
+ // correspond to the transitions.
+ QS60Data::ScanCodeState &scanCodeState = S60->scanCodeStates[keyEvent.iScanCode];
+ switch (scanCodeState) {
+ case QS60Data::Unpressed:
+ switch (type) {
+ case EEventKeyDown:
+ scanCodeState = QS60Data::KeyDown;
+ break;
+ case EEventKey:
+ GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
+ GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
+ break;
+ case EEventKeyUp:
+ // No action.
+ break;
+ }
+ break;
+ case QS60Data::KeyDown:
+ switch (type) {
+ case EEventKeyDown:
+ // This should never happen, just stay in this state to be safe.
+ break;
+ case EEventKey:
+ GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
+ scanCodeState = QS60Data::KeyDownAndKey;
+ break;
+ case EEventKeyUp:
+ scanCodeState = QS60Data::Unpressed;
+ break;
+ }
+ break;
+ case QS60Data::KeyDownAndKey:
+ switch (type) {
+ case EEventKeyDown:
+ // This should never happen, just stay in this state to be safe.
+ break;
+ case EEventKey:
+ GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
+ GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
+ break;
+ case EEventKeyUp:
+ GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
+ scanCodeState = QS60Data::Unpressed;
+ break;
+ }
+ break;
+ }
+ return ret;
+
+#undef GET_RETURN
+}
+
+TKeyResponse QSymbianControl::sendSymbianKeyEvent(const TKeyEvent &keyEvent, QEvent::Type type)
+{
+ // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp
+ // events, we need to cache the keysyms from the EKeyEvent events. This is what
+ // resolveS60ScanCode does.
+ TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode,
+ keyEvent.iCode);
+ int keyCode;
+ if (s60Keysym == EKeyNull){ //some key events have 0 in iCode, for them iScanCode should be used
+ keyCode = qt_keymapper_private()->mapS60ScanCodesToQt(keyEvent.iScanCode);
+ } else if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) {
+ // Normal characters keys.
+ keyCode = s60Keysym;
+ } else {
+ // Special S60 keys.
+ keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym);
+ }
+
+ Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers);
+ QKeyEventEx qKeyEvent(type, keyCode, mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods),
+ (keyEvent.iRepeats != 0), 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers);
+ QWidget *widget;
+ widget = QWidget::keyboardGrabber();
+ if (!widget) {
+ if (QApplicationPrivate::popupWidgets != 0) {
+ widget = QApplication::activePopupWidget()->focusWidget();
+ if (!widget) {
+ widget = QApplication::activePopupWidget();
+ }
+ } else {
+ widget = QApplicationPrivate::focus_widget;
+ if (!widget) {
+ widget = qwidget;
+ }
+ }
+ }
+
+ QEventDispatcherS60 *dispatcher;
+ // It is theoretically possible for someone to install a different event dispatcher.
+ if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) != 0) {
+ if (dispatcher->excludeUserInputEvents()) {
+ dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent));
+ return EKeyWasConsumed;
+ }
+ }
+ return sendKeyEvent(widget, &qKeyEvent);
+}
+
+TKeyResponse QSymbianControl::handleVirtualMouse(const TKeyEvent& keyEvent,TEventCode type)
+{
+#ifndef QT_NO_CURSOR
+ if (S60->mouseInteractionEnabled && S60->virtualMouseRequired) {
+ //translate keys to pointer
+ if ((keyEvent.iScanCode >= EStdKeyLeftArrow && keyEvent.iScanCode <= EStdKeyDownArrow) ||
+ (keyEvent.iScanCode >= EStdKeyDevice10 && keyEvent.iScanCode <= EStdKeyDevice13) ||
+ keyEvent.iScanCode == EStdKeyDevice3) {
+ QPoint pos = QCursor::pos();
+ TPointerEvent fakeEvent;
+ fakeEvent.iType = (TPointerEvent::TType)(-1);
+ fakeEvent.iModifiers = keyEvent.iModifiers;
+ TInt x = pos.x();
+ TInt y = pos.y();
+ if (type == EEventKeyUp) {
+ S60->virtualMouseAccelTimeout.start();
+ switch (keyEvent.iScanCode) {
+ case EStdKeyLeftArrow:
+ S60->virtualMousePressedKeys &= ~QS60Data::Left;
+ break;
+ case EStdKeyRightArrow:
+ S60->virtualMousePressedKeys &= ~QS60Data::Right;
+ break;
+ case EStdKeyUpArrow:
+ S60->virtualMousePressedKeys &= ~QS60Data::Up;
+ break;
+ case EStdKeyDownArrow:
+ S60->virtualMousePressedKeys &= ~QS60Data::Down;
+ break;
+ // diagonal keys (named aliases don't exist in 3.1 SDK)
+ case EStdKeyDevice10:
+ S60->virtualMousePressedKeys &= ~QS60Data::LeftUp;
+ break;
+ case EStdKeyDevice11:
+ S60->virtualMousePressedKeys &= ~QS60Data::RightUp;
+ break;
+ case EStdKeyDevice12:
+ S60->virtualMousePressedKeys &= ~QS60Data::RightDown;
+ break;
+ case EStdKeyDevice13:
+ S60->virtualMousePressedKeys &= ~QS60Data::LeftDown;
+ break;
+ case EStdKeyDevice3: //select
+ if (S60->virtualMousePressedKeys & QS60Data::Select)
+ fakeEvent.iType = TPointerEvent::EButton1Up;
+ S60->virtualMousePressedKeys &= ~QS60Data::Select;
+ break;
+ }
+ }
+ else if (type == EEventKey) {
+ int dx = 0;
+ int dy = 0;
+ if (keyEvent.iScanCode != EStdKeyDevice3) {
+ m_doubleClickTimer.invalidate();
+ //reset mouse accelleration after a short time with no moves
+ const int maxTimeBetweenKeyEventsMs = 500;
+ if (S60->virtualMouseAccelTimeout.isValid() &&
+ S60->virtualMouseAccelTimeout.hasExpired(maxTimeBetweenKeyEventsMs)) {
+ S60->virtualMouseAccelDX = 0;
+ S60->virtualMouseAccelDY = 0;
+ }
+ S60->virtualMouseAccelTimeout.invalidate();
+ }
+ switch (keyEvent.iScanCode) {
+ case EStdKeyLeftArrow:
+ S60->virtualMousePressedKeys |= QS60Data::Left;
+ dx = -1;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case EStdKeyRightArrow:
+ S60->virtualMousePressedKeys |= QS60Data::Right;
+ dx = 1;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case EStdKeyUpArrow:
+ S60->virtualMousePressedKeys |= QS60Data::Up;
+ dy = -1;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case EStdKeyDownArrow:
+ S60->virtualMousePressedKeys |= QS60Data::Down;
+ dy = 1;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case EStdKeyDevice10:
+ S60->virtualMousePressedKeys |= QS60Data::LeftUp;
+ dx = -1;
+ dy = -1;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case EStdKeyDevice11:
+ S60->virtualMousePressedKeys |= QS60Data::RightUp;
+ dx = 1;
+ dy = -1;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case EStdKeyDevice12:
+ S60->virtualMousePressedKeys |= QS60Data::RightDown;
+ dx = 1;
+ dy = 1;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case EStdKeyDevice13:
+ S60->virtualMousePressedKeys |= QS60Data::LeftDown;
+ dx = -1;
+ dy = 1;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case EStdKeyDevice3:
+ // Platform bug. If you start pressing several keys simultaneously (for
+ // example for drag'n'drop), Symbian starts producing spurious up and
+ // down messages for some keys. Therefore, make sure we have a clean slate
+ // of pressed keys before starting a new button press.
+ if (S60->virtualMousePressedKeys & QS60Data::Select) {
+ return EKeyWasConsumed;
+ } else {
+ S60->virtualMousePressedKeys |= QS60Data::Select;
+ fakeEvent.iType = TPointerEvent::EButton1Down;
+ if (m_doubleClickTimer.isValid()
+ && !m_doubleClickTimer.hasExpired(QApplication::doubleClickInterval())) {
+ fakeEvent.iModifiers |= EModifierDoubleClick;
+ m_doubleClickTimer.invalidate();
+ } else {
+ m_doubleClickTimer.start();
+ }
+ }
+ break;
+ }
+ if (dx) {
+ int cdx = S60->virtualMouseAccelDX;
+ //reset accel on change of sign, else double accel
+ if (dx * cdx <= 0)
+ cdx = dx;
+ else
+ cdx *= 4;
+ //cap accelleration
+ if (dx * cdx > S60->virtualMouseMaxAccel)
+ cdx = dx * S60->virtualMouseMaxAccel;
+ //move mouse position
+ x += cdx;
+ S60->virtualMouseAccelDX = cdx;
+ }
+
+ if (dy) {
+ int cdy = S60->virtualMouseAccelDY;
+ if (dy * cdy <= 0)
+ cdy = dy;
+ else
+ cdy *= 4;
+ if (dy * cdy > S60->virtualMouseMaxAccel)
+ cdy = dy * S60->virtualMouseMaxAccel;
+ y += cdy;
+ S60->virtualMouseAccelDY = cdy;
+ }
+ }
+ //clip to screen size (window server allows a sprite hotspot to be outside the screen)
+ int screenNumber = S60->screenNumberForWidget(qwidget);
+ if (x < 0)
+ x = 0;
+ else if (x >= S60->screenWidthInPixelsForScreen[screenNumber])
+ x = S60->screenWidthInPixelsForScreen[screenNumber] - 1;
+ if (y < 0)
+ y = 0;
+ else if (y >= S60->screenHeightInPixelsForScreen[screenNumber])
+ y = S60->screenHeightInPixelsForScreen[screenNumber] - 1;
+ TPoint epos(x, y);
+ TPoint cpos = epos - PositionRelativeToScreen();
+ fakeEvent.iPosition = cpos;
+ fakeEvent.iParentPosition = epos;
+ if(fakeEvent.iType != -1)
+ HandlePointerEvent(fakeEvent);
+ return EKeyWasConsumed;
+ }
+ }
+#endif
+
+ return EKeyWasNotConsumed;
+}
+
+void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent)
+{
+ switch (inputEvent->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent));
+ break;
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseMove:
+ sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent));
+ break;
+ default:
+ // Shouldn't get here.
+ Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown");
+ break;
+ }
+}
+
+TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent)
+{
+#if !defined(QT_NO_IM) && defined(Q_WS_S60)
+ if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) {
+ QInputContext *qic = widget->inputContext();
+ if (qic && qic->filterEvent(keyEvent))
+ return EKeyWasConsumed;
+ }
+#endif // !defined(QT_NO_IM) && defined(Q_OS_SYMBIAN)
+
+ if (widget && qt_sendSpontaneousEvent(widget, keyEvent))
+ if (keyEvent->isAccepted())
+ return EKeyWasConsumed;
+
+ return EKeyWasNotConsumed;
+}
+
+#if !defined(QT_NO_IM) && defined(Q_WS_S60)
+TCoeInputCapabilities QSymbianControl::InputCapabilities() const
+{
+ QWidget *w = 0;
+
+ if (qwidget->hasFocus())
+ w = qwidget;
+ else
+ w = qwidget->focusWidget();
+
+ QCoeFepInputContext *ic;
+ if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled)
+ && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) {
+ return ic->inputCapabilities();
+ } else {
+ return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0);
+ }
+}
+#endif
+
+void QSymbianControl::Draw(const TRect& controlRect) const
+{
+ // Set flag to avoid calling DrawNow in window surface
+ QWidget *window = qwidget->window();
+ Q_ASSERT(window);
+ QTLWExtra *topExtra = window->d_func()->maybeTopData();
+ Q_ASSERT(topExtra);
+
+ TRect wcontrolRect = translateRectForFixedNativeOrientation(controlRect);
+
+ if (!topExtra->inExpose) {
+ topExtra->inExpose = true;
+ if (!qwidget->isWindow()) {
+ // If we get here, then it means we have a native child window
+ // Since no content should ever be painted to these windows, we
+ // erase them with a transparent brush when they get an expose.
+ CWindowGc &gc = SystemGc();
+ gc.SetBrushColor(TRgb(0, 0, 0, 0));
+ gc.Clear(controlRect);
+ }
+ QRect exposeRect = qt_TRect2QRect(wcontrolRect);
+ qwidget->d_func()->syncBackingStore(exposeRect);
+ topExtra->inExpose = false;
+ }
+
+ QWindowSurface *surface = qwidget->windowSurface();
+ QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL;
+
+ if (!engine)
+ return;
+
+ const bool sendNativePaintEvents = qwidget->d_func()->extraData()->receiveNativePaintEvents;
+ if (sendNativePaintEvents) {
+ const QRect r = qt_TRect2QRect(wcontrolRect);
+ QMetaObject::invokeMethod(qwidget, "beginNativePaintEvent", Qt::DirectConnection, Q_ARG(QRect, r));
+ }
+
+ // Map source rectangle into coordinates of the backing store.
+ const QPoint controlBase(controlRect.iTl.iX, controlRect.iTl.iY);
+ const QPoint backingStoreBase = qwidget->mapTo(qwidget->window(), controlBase);
+ const TRect backingStoreRect(TPoint(backingStoreBase.x(), backingStoreBase.y()), controlRect.Size());
+
+ if (engine->type() == QPaintEngine::Raster) {
+ QS60WindowSurface *s60Surface;
+#ifdef QT_GRAPHICSSYSTEM_RUNTIME
+ if (QApplicationPrivate::runtime_graphics_system) {
+ QRuntimeWindowSurface *rtSurface =
+ static_cast<QRuntimeWindowSurface*>(qwidget->windowSurface());
+ s60Surface = static_cast<QS60WindowSurface *>(rtSurface->m_windowSurface.data());
+ } else
+#endif
+ s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface());
+
+ CFbsBitmap *bitmap = s60Surface->symbianBitmap();
+ CWindowGc &gc = SystemGc();
+
+ QWExtra::NativePaintMode nativePaintMode = qwidget->d_func()->extraData()->nativePaintMode;
+ if(qwidget->d_func()->paintOnScreen())
+ nativePaintMode = QWExtra::Disable;
+
+ switch(nativePaintMode) {
+ case QWExtra::Disable:
+ // Do nothing
+ break;
+ case QWExtra::Blit:
+ case QWExtra::BlitWriteAlpha:
+ if (qwidget->d_func()->isOpaque || nativePaintMode == QWExtra::BlitWriteAlpha)
+ gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect);
+ break;
+ case QWExtra::ZeroFill:
+ if (Window().DisplayMode() == EColor16MA
+ || Window().DisplayMode() == Q_SYMBIAN_ECOLOR16MAP) {
+ gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+ gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ gc.SetBrushColor(TRgb::Color16MA(0));
+ gc.Clear(controlRect);
+ } else {
+ gc.SetBrushColor(TRgb(0x000000));
+ gc.Clear(controlRect);
+ };
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ }
+
+ if (sendNativePaintEvents) {
+ const QRect r = qt_TRect2QRect(wcontrolRect);
+ // The draw ops aren't actually sent to WSERV until the graphics
+ // context is deactivated, which happens in the function calling
+ // this one. We therefore delay the delivery of endNativePaintEvent,
+ // to ensure that drawing has completed by the time the widget
+ // receives the event. Note that, if the widget needs to ensure
+ // that the draw ops have actually been executed into the output
+ // framebuffer, a call to RWsSession::Flush is required in the
+ // endNativePaintEvent implementation.
+ QMetaObject::invokeMethod(qwidget, "endNativePaintEvent", Qt::QueuedConnection, Q_ARG(QRect, r));
+ }
+}
+
+void QSymbianControl::qwidgetResize_helper(const QSize &newSize)
+{
+ QRect cr = qwidget->geometry();
+ QSize oldSize(cr.size());
+ cr.setSize(newSize);
+ qwidget->data->crect = cr;
+ if (qwidget->isVisible()) {
+ QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData();
+ bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
+ if (!slowResize && tlwExtra)
+ tlwExtra->inTopLevelResize = true;
+ QResizeEvent e(newSize, oldSize);
+ qt_sendSpontaneousEvent(qwidget, &e);
+ if (!qwidget->testAttribute(Qt::WA_StaticContents))
+ qwidget->d_func()->syncBackingStore();
+ if (!slowResize && tlwExtra)
+ tlwExtra->inTopLevelResize = false;
+ } else {
+ if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) {
+ QResizeEvent *e = new QResizeEvent(newSize, oldSize);
+ QApplication::postEvent(qwidget, e);
+ }
+ }
+}
+
+void QSymbianControl::SizeChanged()
+{
+ CCoeControl::SizeChanged();
+
+ // When FixNativeOrientation had been called, the RWindow/CCoeControl size
+ // and the surface/QWidget size have nothing to do with each other.
+ if (qwidget->d_func()->fixNativeOrientationCalled)
+ return;
+
+ QSize oldSize = qwidget->size();
+ QSize newSize(Size().iWidth, Size().iHeight);
+
+ if (oldSize != newSize) {
+ // Enforce the proper size for fullscreen widgets on the secondary screen.
+ const bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
+ const int screenNumber = S60->screenNumberForWidget(qwidget);
+ if (!m_inExternalScreenOverride && isFullscreen && screenNumber > 0) {
+ int screenWidth = S60->screenWidthInPixelsForScreen[screenNumber];
+ int screenHeight = S60->screenHeightInPixelsForScreen[screenNumber];
+ TSize screenSize(screenWidth, screenHeight);
+ if (screenWidth > 0 && screenHeight > 0 && screenSize != Size()) {
+ m_inExternalScreenOverride = true;
+ SetExtent(TPoint(0, 0), screenSize);
+ return;
+ }
+ }
+
+ qwidgetResize_helper(newSize);
+ }
+
+ m_inExternalScreenOverride = false;
+
+ // CCoeControl::SetExtent calls SizeChanged, but does not call
+ // PositionChanged, so we call it here to ensure that the widget's
+ // position is updated.
+ PositionChanged();
+}
+
+void QSymbianControl::PositionChanged()
+{
+ CCoeControl::PositionChanged();
+
+ QPoint oldPos = qwidget->geometry().topLeft();
+ QPoint newPos(Position().iX, Position().iY);
+
+ if (oldPos != newPos) {
+ QRect cr = qwidget->geometry();
+ cr.moveTopLeft(newPos);
+ qwidget->data->crect = cr;
+ QTLWExtra *top = qwidget->d_func()->maybeTopData();
+ if (top && (qwidget->windowState() & (~Qt::WindowActive)) == Qt::WindowNoState)
+ top->normalGeometry.moveTopLeft(newPos);
+ if (qwidget->isVisible()) {
+ QMoveEvent e(newPos, oldPos);
+ qt_sendSpontaneousEvent(qwidget, &e);
+ } else {
+ QMoveEvent * e = new QMoveEvent(newPos, oldPos);
+ QApplication::postEvent(qwidget, e);
+ }
+ }
+}
+
+void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
+{
+ if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
+ return;
+
+#ifdef Q_WS_S60
+ if (S60->splitViewLastWidget)
+ return;
+#endif
+
+ // Popups never get focused, but still receive the FocusChanged when they are hidden.
+ if (QApplicationPrivate::popupWidgets != 0
+ || (qwidget->windowType() & Qt::Popup) == Qt::Popup)
+ return;
+
+ if (IsFocused() && IsVisible()) {
+ if (m_symbianPopupIsOpen) {
+ QWidget *fw = QApplication::focusWidget();
+ if (fw) {
+ QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
+ QCoreApplication::sendEvent(fw, &event);
+ }
+ m_symbianPopupIsOpen = false;
+ }
+
+ QApplication::setActiveWindow(qwidget->window());
+ qwidget->d_func()->setWindowIcon_sys(true);
+ qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
+#ifdef Q_WS_S60
+ if (qwidget->isWindow())
+ S60->setRecursiveDecorationsVisibility(qwidget, qwidget->windowState());
+#endif
+ } else if (QApplication::activeWindow() == qwidget->window()) {
+ bool focusedControlFound = false;
+ WId winId = 0;
+ for (QWidget *w = qwidget->parentWidget(); w && (winId = w->internalWinId()); w = w->parentWidget()) {
+ if (winId->IsFocused() && winId->IsVisible()) {
+ focusedControlFound = true;
+ break;
+ } else if (w->isWindow())
+ break;
+ }
+ if (!focusedControlFound) {
+ if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) {
+ QWidget *fw = QApplication::focusWidget();
+ if (fw) {
+ QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
+ QCoreApplication::sendEvent(fw, &event);
+ }
+ m_symbianPopupIsOpen = true;
+ return;
+ }
+
+ QApplication::setActiveWindow(0);
+ }
+ }
+ // else { We don't touch the active window unless we were explicitly activated or deactivated }
+}
+
+void QSymbianControl::handleClientAreaChange()
+{
+ const bool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
+ if (qwidget->isFullScreen() && !cbaVisibilityHint) {
+ SetExtentToWholeScreen();
+ } else if (qwidget->isMaximized() || (qwidget->isFullScreen() && cbaVisibilityHint)) {
+ TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
+ SetExtent(r.iTl, r.Size());
+ } else if (!qwidget->isMinimized()) { // Normal geometry
+ if (!qwidget->testAttribute(Qt::WA_Resized)) {
+ qwidget->adjustSize();
+ qwidget->setAttribute(Qt::WA_Resized, false); //not a user resize
+ }
+ if (!qwidget->testAttribute(Qt::WA_Moved) && qwidget->windowType() != Qt::Dialog) {
+ TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
+ SetPosition(r.iTl);
+ qwidget->setAttribute(Qt::WA_Moved, false); // not really an explicit position
+ }
+ }
+}
+
+bool QSymbianControl::isSplitViewWidget(QWidget *widget) {
+ bool returnValue = true;
+ //Ignore events sent to non-active windows, not visible widgets and not parents of input widget.
+ if (!qwidget->isActiveWindow()
+ || !qwidget->isVisible()
+ || !qwidget->isAncestorOf(widget)) {
+
+ returnValue = false;
+ }
+ return returnValue;
+}
+
+void QSymbianControl::HandleResourceChange(int resourceType)
+{
+ switch (resourceType) {
+ case KSplitViewCloseEvent: //intentional fall-through
+ case KSplitViewOpenEvent: {
+#if !defined(QT_NO_IM) && defined(Q_WS_S60)
+
+ //Fetch widget getting the text input
+ QWidget *widget = QWidget::keyboardGrabber();
+ if (!widget) {
+ if (QApplicationPrivate::popupWidgets) {
+ widget = QApplication::activePopupWidget()->focusWidget();
+ if (!widget) {
+ widget = QApplication::activePopupWidget();
+ }
+ } else {
+ widget = QApplicationPrivate::focus_widget;
+ if (!widget) {
+ widget = qwidget;
+ }
+ }
+ }
+ if (widget) {
+ QCoeFepInputContext *ic = qobject_cast<QCoeFepInputContext *>(widget->inputContext());
+ if (!ic) {
+ ic = qobject_cast<QCoeFepInputContext *>(qApp->inputContext());
+ }
+ if (ic && isSplitViewWidget(widget)) {
+ if (resourceType == KSplitViewCloseEvent) {
+ ic->resetSplitViewWidget();
+ } else {
+ ic->ensureFocusWidgetVisible(widget);
+ }
+ }
+ }
+#endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
+ }
+ break;
+ case KInternalStatusPaneChange:
+ // When status pane is not visible, only handle client area change if status pane was
+ // previously visible, as size changes to hidden status pane should not affect
+ // client area.
+ if (S60->statusPane() && (S60->statusPane()->IsVisible() || m_lastStatusPaneVisibility)) {
+ m_lastStatusPaneVisibility = S60->statusPane()->IsVisible();
+ handleClientAreaChange();
+ }
+ if (IsFocused() && IsVisible()) {
+ qwidget->d_func()->setWindowIcon_sys(true);
+ qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
+ }
+ break;
+ case KUidValueCoeFontChangeEvent:
+ // font change event
+ break;
+#ifdef Q_WS_S60
+ case KEikDynamicLayoutVariantSwitch:
+ {
+ handleClientAreaChange();
+ // Send resize event to trigger desktopwidget workAreaResized signal
+ if (qt_desktopWidget) {
+ QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size());
+ QApplication::sendEvent(qt_desktopWidget, &e);
+ }
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+
+ CCoeControl::HandleResourceChange(resourceType);
+
+}
+void QSymbianControl::CancelLongTapTimer()
+{
+ m_longTapDetector->Cancel();
+}
+
+TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id)
+{
+ if (id.iUid == ETypeId)
+ return id.MakePtr(this);
+
+ return CCoeControl::MopSupplyObject(id);
+}
+
+void QSymbianControl::setFocusSafely(bool focus)
+{
+ // The stack hack in here is very unfortunate, but it is the only way to ensure proper
+ // focus in Symbian. If this is not executed, the control which happens to be on
+ // the top of the stack may randomly be assigned focus by Symbian, for example
+ // when creating new windows (specifically in CCoeAppUi::HandleStackChanged()).
+
+ // Close any popups.
+ CEikonEnv::Static()->EikAppUi()->StopDisplayingMenuBar();
+
+ if (focus) {
+ S60->appUi()->RemoveFromStack(this);
+ // Symbian doesn't automatically remove focus from the last focused control, so we need to
+ // remember it and clear focus ourselves.
+ if (lastFocusedControl && lastFocusedControl != this)
+ lastFocusedControl->SetFocus(false);
+ QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
+ ECoeStackPriorityDefault + 1, ECoeStackFlagStandard)); // Note the + 1
+ lastFocusedControl = this;
+ this->SetFocus(true);
+ } else {
+ S60->appUi()->RemoveFromStack(this);
+ QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
+ ECoeStackPriorityDefault, ECoeStackFlagStandard));
+ if(this == lastFocusedControl)
+ lastFocusedControl = 0;
+ this->SetFocus(false);
+ }
+}
+
+bool QSymbianControl::isControlActive()
+{
+ return IsActivated() ? true : false;
+}
+
+void QSymbianControl::ensureFixNativeOrientation()
+{
+#if defined(Q_SYMBIAN_SUPPORTS_FIXNATIVEORIENTATION)
+ if (!qwidget->isWindow() || qwidget->windowType() == Qt::Desktop)
+ return;
+ if (S60->screenNumberForWidget(qwidget) > 0)
+ return;
+ const bool isFixed = qwidget->d_func()->fixNativeOrientationCalled;
+ const bool isFixEnabled = qwidget->testAttribute(Qt::WA_SymbianNoSystemRotation);
+ const bool isFullScreen = qwidget->windowState().testFlag(Qt::WindowFullScreen);
+ if (isFullScreen && isFixEnabled) {
+ const bool surfaceBasedGs =
+ QApplicationPrivate::graphics_system_name == QLatin1String("openvg")
+ || QApplicationPrivate::graphics_system_name == QLatin1String("opengl");
+ if (!surfaceBasedGs)
+ qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
+ if (!isFixed && surfaceBasedGs) {
+ if (Window().FixNativeOrientation() == KErrNone) {
+ qwidget->d_func()->fixNativeOrientationCalled = true;
+ // The EGL window surface is now fixed to the native orientation
+ // of the device, no matter what size we pass when creating it.
+ // Enforce the same size for the QWidget too. For the underlying
+ // CCoeControl and RWindow it is up to the system to resize them
+ // when the standard auto-rotation mechanism is in use, we must not
+ // change that behavior by forcing any size for those. In practice
+ // this means that the QWidget and the underlying native control
+ // dimensions will be out of sync when FixNativeOrientation was
+ // called and the device is turned to the non-native (typically
+ // landscape) orientation. The pointer event handling and certain
+ // functions like Draw() will need to compensate for this.
+ QSize newSize(S60->nativeScreenWidthInPixels, S60->nativeScreenHeightInPixels);
+ if (qwidget->size() != newSize)
+ qwidgetResize_helper(newSize);
+ } else {
+ qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
+ }
+ }
+ } else if (isFixed) {
+ qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
+ qwidget->d_func()->fixNativeOrientationCalled = false;
+ qwidget->hide();
+ qwidget->d_func()->create_sys(0, false, true);
+ qwidget->show();
+ }
+#else
+ qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
+#endif
+}
+
+/*!
+ \typedef QApplication::QS60MainApplicationFactory
+ \since 4.6
+
+ This is a typedef for a pointer to a function with the following
+ signature:
+
+ \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 47
+
+ \sa QApplication::QApplication()
+*/
+
+/*!
+ \since 4.6
+
+ Creates an application using the application factory given in
+ \a factory, and using \a argc command line arguments in \a argv.
+ \a factory can be leaving, but the error will be converted to a
+ standard exception.
+
+ This function is only available on S60.
+*/
+QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv)
+ : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient, 0x040000))
+{
+ Q_D(QApplication);
+ S60->s60ApplicationFactory = factory;
+ d->construct();
+}
+
+QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int _internal)
+ : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient, _internal))
+{
+ Q_D(QApplication);
+ S60->s60ApplicationFactory = factory;
+ d->construct();
+ QApplicationPrivate::app_compile_version = _internal;
+}
+
+void qt_init(QApplicationPrivate * /* priv */, int)
+{
+ if (!CCoeEnv::Static()) {
+ // The S60 framework creates a new trap handler which will render any existing traps
+ // invalid as long as it is active. This means that all code in main() that occurs after
+ // the QApplication construction needs to be surrounded by a new trap, despite having
+ // an outer one already. To avoid this, we save the original trap handler here, and set
+ // it back after the S60 framework is constructed. Then we restore it right before the S60
+ // framework destruction.
+ TTrapHandler *origTrapHandler = User::TrapHandler();
+
+ // The S60 framework has not been initialized. We need to do it.
+ TApaApplicationFactory factory(S60->s60ApplicationFactory ?
+ S60->s60ApplicationFactory : newS60Application);
+ CApaCommandLine* commandLine = q_check_ptr(QCoreApplicationPrivate::symbianCommandLine());
+ if (commandLine) {
+ // After this construction, CEikonEnv will be available from CEikonEnv::Static().
+ // (much like our qApp).
+ QtEikonEnv* coe = new QtEikonEnv;
+ //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there.
+ TRAPD(err, coe->ConstructAppFromCommandLineL(factory, *commandLine));
+ if(err != KErrNone) {
+ qWarning() << "qt_init: Eikon application construct failed ("
+ << err
+ << "), maybe missing resource file on S60 3.1?";
+ delete coe;
+ qt_symbian_throwIfError(err);
+ }
+ }
+
+ S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler);
+
+ S60->qtOwnsS60Environment = true;
+ } else {
+ S60->qtOwnsS60Environment = false;
+ }
+
+#ifdef QT_NO_DEBUG
+ if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty())
+#endif
+ S60->wsSession().SetAutoFlush(ETrue);
+
+#ifdef Q_SYMBIAN_WINDOW_SIZE_CACHE
+ TRAP_IGNORE(S60->wsSession().EnableWindowSizeCacheL());
+#endif
+
+ S60->updateScreenSize();
+
+
+ TDisplayMode mode = S60->screenDevice()->DisplayMode();
+ S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode);
+
+ //NB: RWsSession::GetColorModeList tells you what window modes are supported,
+ //not what bitmap formats.
+ if(QSysInfo::symbianVersion() == QSysInfo::SV_9_2)
+ S60->supportsPremultipliedAlpha = 0;
+ else
+ S60->supportsPremultipliedAlpha = 1;
+
+ RProcess me;
+ TSecureId securId = me.SecureId();
+ S60->uid = securId.operator TUid();
+
+ // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app,
+ // and for dimming behind modal windows
+ S60->windowGroup().EnableFocusChangeEvents();
+
+ //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this)
+ const TInt KMachineUidSamsungI8510 = 0x2000C51E;
+ // HAL::Get(HALData::EPen, TInt& result) may set 'result' to 1 on some 3.1 systems (e.g. N95).
+ // But we know that S60 systems below 5.0 did not support touch.
+ static const bool touchIsUnsupportedOnSystem =
+ QSysInfo::s60Version() == QSysInfo::SV_S60_3_1
+ || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2;
+ TInt machineUID;
+ TInt mouse;
+ TInt touch;
+ TInt err;
+ err = HAL::Get(HALData::EMouse, mouse);
+ if (err != KErrNone)
+ mouse = 0;
+ err = HAL::Get(HALData::EMachineUid, machineUID);
+ if (err != KErrNone)
+ machineUID = 0;
+ err = HAL::Get(HALData::EPen, touch);
+ if (err != KErrNone || touchIsUnsupportedOnSystem)
+ touch = 0;
+#ifdef __WINS__
+ if(QSysInfo::symbianVersion() <= QSysInfo::SV_9_4) {
+ //for symbian SDK emulator, force values to match typical devices.
+ mouse = 0;
+ touch = touchIsUnsupportedOnSystem ? 0 : 1;
+ }
+#endif
+ if (mouse || machineUID == KMachineUidSamsungI8510) {
+ S60->hasTouchscreen = false;
+ S60->virtualMouseRequired = false;
+ }
+ else if (!touch) {
+ S60->hasTouchscreen = false;
+ S60->virtualMouseRequired = true;
+ }
+ else {
+ S60->hasTouchscreen = true;
+ S60->virtualMouseRequired = false;
+ }
+
+ S60->avkonComponentsSupportTransparency = false;
+ S60->menuBeingConstructed = false;
+
+#ifdef Q_WS_S60
+ TUid KCRUidAvkon = { 0x101F876E };
+ TUint32 KAknAvkonTransparencyEnabled = 0x0000000D;
+
+ CRepository* repository = 0;
+ TRAP(err, repository = CRepository::NewL(KCRUidAvkon));
+
+ if(err == KErrNone) {
+ TInt value = 0;
+ err = repository->Get(KAknAvkonTransparencyEnabled, value);
+ if(err == KErrNone) {
+ S60->avkonComponentsSupportTransparency = (value==1) ? true : false;
+ }
+ }
+ delete repository;
+ repository = 0;
+#endif
+
+ qt_keymapper_private()->updateInputLanguage();
+
+#ifdef QT_KEYPAD_NAVIGATION
+ if (touch) {
+ QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
+ } else {
+ QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional;
+ }
+#endif
+
+#ifndef QT_NO_CURSOR
+ //Check if window server pointer cursors are supported or not
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ //In generic binary, use the HAL and OS version
+ //Any other known good phones should be added here.
+ if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4
+ && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion()
+ != QSysInfo::SV_9_2)) {
+ S60->brokenPointerCursors = false;
+ qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
+ }
+ else
+ S60->brokenPointerCursors = true;
+#endif
+
+ if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors) {
+ qt_symbian_set_pointer_sprite(Qt::ArrowCursor);
+ qt_symbian_show_pointer_sprite();
+ }
+ else
+#endif
+ S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
+ }
+#endif
+
+ QFont systemFont;
+ systemFont.setFamily(systemFont.defaultFamily());
+ QApplicationPrivate::setSystemFont(systemFont);
+
+ QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit()));
+
+#ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = true;
+
+ const TUid KIvePropertyCat = {0x2726beef};
+ enum TIvePropertyChipType {
+ EVCBCM2727B1 = 0x00000000,
+ EVCBCM2763A0 = 0x04000100,
+ EVCBCM2763B0 = 0x04000102,
+ EVCBCM2763C0 = 0x04000103,
+ EVCBCM2763C1 = 0x04000104,
+ EVCBCMUnknown = 0x7fffffff
+ };
+
+ TInt chipType = EVCBCMUnknown;
+ if (RProperty::Get(KIvePropertyCat, 0 /*chip type*/, chipType) == KErrNone) {
+ if (chipType == EVCBCM2727B1) {
+ // We have only 32MB GPU memory. Use raster surfaces
+ // for transparent TLWs.
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+ }
+ } else {
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+ }
+ if (QApplicationPrivate::graphics_system_name == QLatin1String("raster"))
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+#else
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+#endif
+/*
+ ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
+ int argc = priv->argc;
+ char **argv = priv->argv;
+
+ // Get command line params
+ int j = argc ? 1 : 0;
+ for (int i=1; i<argc; i++) {
+ if (argv[i] && *argv[i] != '-') {
+ argv[j++] = argv[i];
+ continue;
+ }
+
+#if defined(QT_DEBUG)
+ if (qstrcmp(argv[i], "-nograb") == 0)
+ appNoGrab = !appNoGrab;
+ else
+#endif // QT_DEBUG
+ ;
+ }
+*/
+
+ // Register WId with the metatype system. This is to enable
+ // QWidgetPrivate::create_sys to used delayed slot invocation in order
+ // to destroy WId objects during reparenting.
+ qRegisterMetaType<WId>("WId");
+}
+
+#ifdef QT_NO_FREETYPE
+extern void qt_cleanup_symbianFontDatabase(); // qfontdatabase_s60.cpp
+#endif
+
+/*****************************************************************************
+ qt_cleanup() - cleans up when the application is finished
+ *****************************************************************************/
+void qt_cleanup()
+{
+#ifdef Q_WS_S60
+ S60->setButtonGroupContainer(0);
+#endif
+ if(qt_S60Beep) {
+ delete qt_S60Beep;
+ qt_S60Beep = 0;
+ }
+ QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles
+ QPixmapCache::clear(); // Has to happen now, since QS60PixmapData has FBS handles
+
+#ifdef QT_NO_FREETYPE
+ qt_cleanup_symbianFontDatabase();
+#endif
+// S60 structure and window server session are freed in eventdispatcher destructor as they are needed there
+
+ // It's important that this happens here, before the event dispatcher gets
+ // deleted, because the input context needs the event loop one last time before
+ // it dies.
+ delete QApplicationPrivate::inputContext;
+ QApplicationPrivate::inputContext = 0;
+
+ //Change mouse pointer back
+ S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
+
+#ifdef Q_WS_S60
+ // Clear CBA
+ CEikonEnv::Static()->AppUiFactory()->SwapButtonGroup(0);
+ delete S60->buttonGroupContainer();
+ S60->setButtonGroupContainer(0);
+#endif
+
+ // Call EndFullScreen() to prevent confusing the system effect state machine.
+ qt_endFullScreenEffect();
+
+ if (S60->qtOwnsS60Environment) {
+ // Restore the S60 framework trap handler. See qt_init().
+ User::SetTrapHandler(S60->s60InstalledTrapHandler);
+
+ CEikonEnv* coe = CEikonEnv::Static();
+ coe->PrepareToExit();
+ // The CEikonEnv itself is destroyed in here.
+ coe->DestroyEnvironment();
+ }
+}
+
+void QApplicationPrivate::initializeWidgetPaletteHash()
+{
+ // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash()
+ // Possibly a task fot the S60Style guys
+}
+
+void QApplicationPrivate::createEventDispatcher()
+{
+ Q_Q(QApplication);
+ eventDispatcher = new QEventDispatcherS60(q);
+}
+
+QString QApplicationPrivate::appName() const
+{
+ return QCoreApplicationPrivate::appName();
+}
+
+bool QApplicationPrivate::modalState()
+{
+ return app_do_modal;
+}
+
+void QApplicationPrivate::enterModal_sys(QWidget *widget)
+{
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
+ S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeEnter);
+#endif
+ if (widget) {
+ static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(ETrue);
+ // Modal partial screen dialogs (like queries) capture pointer events.
+ // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
+ widget->effectiveWinId()->SetGloballyCapturing(ETrue);
+ widget->effectiveWinId()->SetPointerCapture(ETrue);
+ }
+ if (!qt_modal_stack)
+ qt_modal_stack = new QWidgetList;
+ qt_modal_stack->insert(0, widget);
+ app_do_modal = true;
+}
+
+void QApplicationPrivate::leaveModal_sys(QWidget *widget)
+{
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
+ S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeExit);
+#endif
+ if (widget) {
+ static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(EFalse);
+ // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
+ widget->effectiveWinId()->SetGloballyCapturing(EFalse);
+ widget->effectiveWinId()->SetPointerCapture(EFalse);
+ }
+ if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
+ if (qt_modal_stack->isEmpty()) {
+ delete qt_modal_stack;
+ qt_modal_stack = 0;
+ }
+ }
+ app_do_modal = qt_modal_stack != 0;
+}
+
+void QApplicationPrivate::openPopup(QWidget *popup)
+{
+ if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
+ static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(ETrue);
+
+ if (!QApplicationPrivate::popupWidgets)
+ QApplicationPrivate::popupWidgets = new QWidgetList;
+ QApplicationPrivate::popupWidgets->append(popup);
+
+ // Cancel focus widget pointer capture and long tap timer
+ if (QApplication::focusWidget()) {
+ static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer();
+ QApplication::focusWidget()->effectiveWinId()->SetPointerCapture(false);
+ }
+
+ if (!qt_nograb()) {
+ // Cancel pointer capture and long tap timer for earlier popup
+ int popupCount = QApplicationPrivate::popupWidgets->count();
+ if (popupCount > 1) {
+ QWidget* prevPopup = QApplicationPrivate::popupWidgets->at(popupCount-2);
+ static_cast<QSymbianControl*>(prevPopup->effectiveWinId())->CancelLongTapTimer();
+ prevPopup->effectiveWinId()->SetPointerCapture(false);
+ }
+
+ // Enable pointer capture for this (topmost) popup
+ Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
+ WId id = popup->effectiveWinId();
+ id->SetPointerCapture(true);
+ }
+
+ // popups are not focus-handled by the window system (the first
+ // popup grabbed the keyboard), so we have to do that manually: A
+ // new popup gets the focus
+ QWidget *fw = popup->focusWidget();
+ if (fw) {
+ fw->setFocus(Qt::PopupFocusReason);
+ } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
+ fw = QApplication::focusWidget();
+ if (fw) {
+ QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
+ q_func()->sendEvent(fw, &e);
+ }
+ }
+}
+
+void QApplicationPrivate::closePopup(QWidget *popup)
+{
+ if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
+ static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(EFalse);
+
+ if (!QApplicationPrivate::popupWidgets)
+ return;
+ QApplicationPrivate::popupWidgets->removeAll(popup);
+
+ // Cancel pointer capture and long tap for this popup
+ WId id = popup->effectiveWinId();
+ id->SetPointerCapture(false);
+ static_cast<QSymbianControl*>(id)->CancelLongTapTimer();
+
+ if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
+ delete QApplicationPrivate::popupWidgets;
+ QApplicationPrivate::popupWidgets = 0;
+ if (!qt_nograb()) { // grabbing not disabled
+ Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
+ if (QWidgetPrivate::mouseGrabber != 0)
+ QWidgetPrivate::mouseGrabber->grabMouse();
+
+ if (QWidgetPrivate::keyboardGrabber != 0)
+ QWidgetPrivate::keyboardGrabber->grabKeyboard();
+
+ QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
+ : q_func()->focusWidget();
+ if (fw) {
+ if(fw->window()->isModal()) // restore pointer capture for modal window
+ fw->effectiveWinId()->SetPointerCapture(true);
+
+ if (fw != q_func()->focusWidget()) {
+ fw->setFocus(Qt::PopupFocusReason);
+ } else {
+ QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
+ q_func()->sendEvent(fw, &e);
+ }
+ }
+ }
+ } else {
+
+ // popups are not focus-handled by the window system (the
+ // first popup grabbed the keyboard), so we have to do that
+ // manually: A popup was closed, so the previous popup gets
+ // the focus.
+ QWidget* aw = QApplicationPrivate::popupWidgets->last();
+ if (QWidget *fw = QApplication::focusWidget()) {
+ QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
+ q_func()->sendEvent(fw, &e);
+ }
+
+ // Enable pointer capture for previous popup
+ if (aw) {
+ aw->effectiveWinId()->SetPointerCapture(true);
+ }
+ }
+}
+
+QWidget * QApplication::topLevelAt(QPoint const& point)
+{
+ QWidget *found = 0;
+ int lowestZ = INT_MAX;
+ QWidgetList list = QApplication::topLevelWidgets();
+ for (int i = 0; i < list.count(); ++i) {
+ QWidget *widget = list.at(i);
+ if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
+ Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
+ if (widget->geometry().adjusted(0,0,1,1).contains(point)) {
+ // At this point we know there is a Qt widget under the point.
+ // Now we need to make sure it is the top most in the z-order.
+ RDrawableWindow *const window = widget->effectiveWinId()->DrawableWindow();
+ int z = window->OrdinalPosition();
+ if (z < lowestZ) {
+ lowestZ = z;
+ found = widget;
+ }
+ }
+ }
+ }
+ return found;
+}
+
+void QApplication::alert(QWidget * /* widget */, int /* duration */)
+{
+ // TODO: Implement QApplication::alert(QWidget *widget, int duration)
+}
+
+int QApplication::doubleClickInterval()
+{
+ TTimeIntervalMicroSeconds32 us;
+ TInt distance;
+ S60->wsSession().GetDoubleClickSettings(us, distance);
+ return (us.Int() / 1000);
+}
+
+void QApplication::setDoubleClickInterval(int ms)
+{
+ TTimeIntervalMicroSeconds32 newUs( ms * 1000);
+ TTimeIntervalMicroSeconds32 us;
+ TInt distance;
+ S60->wsSession().GetDoubleClickSettings(us, distance);
+ if (us != newUs)
+ S60->wsSession().SetDoubleClick(newUs, distance);
+}
+
+int QApplication::keyboardInputInterval()
+{
+ return QApplicationPrivate::keyboard_input_time;
+}
+
+void QApplication::setKeyboardInputInterval(int ms)
+{
+ QApplicationPrivate::keyboard_input_time = ms;
+}
+
+int QApplication::cursorFlashTime()
+{
+ return QApplicationPrivate::cursor_flash_time;
+}
+
+void QApplication::setCursorFlashTime(int msecs)
+{
+ QApplicationPrivate::cursor_flash_time = msecs;
+}
+
+void QApplication::beep()
+{
+ if (!qt_S60Beep) {
+ TInt frequency = 880;
+ TTimeIntervalMicroSeconds duration(500000);
+ TRAP_IGNORE(qt_S60Beep=QS60Beep::NewL(frequency, duration));
+ }
+ if (qt_S60Beep)
+ qt_S60Beep->Play();
+}
+
+static inline bool callSymbianEventFilters(const QSymbianEvent *event)
+{
+ long unused;
+ return qApp->filterEvent(const_cast<QSymbianEvent *>(event), &unused);
+}
+
+/*!
+ \warning This function is only available on Symbian.
+ \since 4.6
+
+ This function processes an individual Symbian event
+ \a event. It returns 1 if the event was handled, 0 if
+ the \a event was not handled, and -1 if the event was
+ not handled because the event is not known to Qt.
+ */
+
+int QApplication::symbianProcessEvent(const QSymbianEvent *event)
+{
+ Q_D(QApplication);
+
+ QScopedLoopLevelCounter counter(d->threadData);
+
+ if (d->eventDispatcher->filterEvent(const_cast<QSymbianEvent *>(event)))
+ return 1;
+
+ QWidget *w = qApp ? qApp->focusWidget() : 0;
+ if (w) {
+ QInputContext *ic = w->inputContext();
+ if (ic && ic->symbianFilterEvent(w, event))
+ return 1;
+ }
+
+ if (symbianEventFilter(event))
+ return 1;
+
+ switch (event->type()) {
+ case QSymbianEvent::WindowServerEvent:
+ return d->symbianProcessWsEvent(event);
+ case QSymbianEvent::CommandEvent:
+ return d->symbianHandleCommand(event);
+ case QSymbianEvent::ResourceChangeEvent:
+ return d->symbianResourceChange(event);
+ default:
+ return -1;
+ }
+}
+
+int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent)
+{
+ // Qt event handling. Handle some events regardless of if the handle is in our
+ // widget map or not.
+ const TWsEvent *event = symbianEvent->windowServerEvent();
+ CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle());
+ const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control);
+ switch (event->Type()) {
+ case EEventPointerEnter:
+ if (controlInMap) {
+ callSymbianEventFilters(symbianEvent);
+ return 1; // Qt::Enter will be generated in HandlePointerL
+ }
+ break;
+ case EEventPointerExit:
+ if (controlInMap) {
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+ if (S60) {
+ // mouseEvent outside our window, send leave event to last focused widget
+ QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos,
+ Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier);
+ if (S60->lastPointerEventTarget)
+ qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent);
+ S60->lastPointerEventTarget = 0;
+ }
+ return 1;
+ }
+ break;
+ case EEventScreenDeviceChanged: // fallthrough
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ case EEventDisplayChanged:
+#endif
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+ if (S60)
+ S60->updateScreenSize();
+ if (qt_desktopWidget) {
+ QSize oldSize = qt_desktopWidget->size();
+ qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels);
+ qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels);
+ QResizeEvent e(qt_desktopWidget->size(), oldSize);
+ QApplication::sendEvent(qt_desktopWidget, &e);
+ }
+ return 0; // Propagate to CONE
+ case EEventWindowVisibilityChanged:
+ if (controlInMap) {
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+ const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
+ if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible)
+ S60->controlVisibilityChanged(control, false);
+ else if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
+ S60->controlVisibilityChanged(control, true);
+ return 1;
+ }
+ break;
+ case EEventFocusGained:
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+#ifndef QT_NO_CURSOR
+ //re-enable mouse interaction
+ if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors)
+ qt_symbian_show_pointer_sprite();
+ else
+#endif
+ S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
+ }
+#endif
+#ifdef QT_SOFTKEYS_ENABLED
+ if (!CEikonEnv::Static()->EikAppUi()->IsDisplayingMenuOrDialog())
+ QSoftKeyManager::updateSoftKeys();
+#endif
+ break;
+ case EEventFocusLost:
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+#ifndef QT_NO_CURSOR
+ //disable mouse as may be moving to application that does not support it
+ if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors)
+ qt_symbian_hide_pointer_sprite();
+ else
+#endif
+ S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
+ }
+#endif
+ break;
+ case KGoomMemoryLowEvent:
+#ifdef QT_DEBUG
+ qDebug() << "QApplicationPrivate::symbianProcessWsEvent - KGoomMemoryLowEvent";
+#endif
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+#ifdef QT_GRAPHICSSYSTEM_RUNTIME
+ if(QApplicationPrivate::runtime_graphics_system) {
+ bool switchToSwRendering(false);
+
+ foreach (QWidget *w, QApplication::topLevelWidgets()) {
+ if(w->d_func()->topData()->backingStore) {
+ switchToSwRendering = true;
+ break;
+ }
+ }
+
+ if (switchToSwRendering) {
+ QRuntimeGraphicsSystem *gs =
+ static_cast<QRuntimeGraphicsSystem*>(QApplicationPrivate::graphics_system);
+ gs->setGraphicsSystem(QLatin1String("raster"));
+ }
+ }
+#endif
+ break;
+ case KGoomMemoryGoodEvent:
+#ifdef QT_DEBUG
+ qDebug() << "QApplicationPrivate::symbianProcessWsEvent - KGoomMemoryGoodEvent";
+#endif
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+#ifdef QT_GRAPHICSSYSTEM_RUNTIME
+ if(QApplicationPrivate::runtime_graphics_system) {
+ QRuntimeGraphicsSystem *gs =
+ static_cast<QRuntimeGraphicsSystem*>(QApplicationPrivate::graphics_system);
+ gs->setGraphicsSystem(QLatin1String("openvg"));
+ }
+#endif
+ break;
+#ifdef Q_SYMBIAN_SUPPORTS_SURFACES
+ case EEventUser:
+ {
+ // GOOM is looking for candidates to kill so indicate that we are
+ // capable of cleaning up by handling this event
+ TInt32 *data = reinterpret_cast<TInt32 *>(event->EventData());
+ if (data[0] == EApaSystemEventShutdown && data[1] == KGoomMemoryLowEvent)
+ return 1;
+ }
+ break;
+#endif
+
+#ifdef Q_WS_S60
+ case KEikInputLanguageChange:
+ qt_keymapper_private()->updateInputLanguage();
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ if (!controlInMap)
+ return -1;
+
+ return 0;
+}
+
+/*!
+ \warning This virtual function is only available on Symbian.
+ \since 4.6
+
+ If you create an application that inherits QApplication and reimplement
+ this function, you get direct access to events that the are received
+ from Symbian. The events are passed in the \a event parameter.
+
+ Return true if you want to stop the event from being processed. Return
+ false for normal event dispatching. The default implementation returns
+ false, and does nothing with \a event.
+ */
+bool QApplication::symbianEventFilter(const QSymbianEvent *event)
+{
+ Q_UNUSED(event);
+ return false;
+}
+
+/*!
+ \warning This function is only available on Symbian.
+ \since 4.6
+
+ Handles \a{command}s which are typically handled by
+ CAknAppUi::HandleCommandL(). Qts Ui integration into Symbian is
+ partially achieved by deriving from CAknAppUi. Currently, exit,
+ menu and softkey commands are handled.
+
+ \sa s60EventFilter(), s60ProcessEvent()
+*/
+int QApplicationPrivate::symbianHandleCommand(const QSymbianEvent *symbianEvent)
+{
+ Q_Q(QApplication);
+ int ret = 0;
+
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+
+ int command = symbianEvent->command();
+
+ switch (command) {
+#ifdef Q_WS_S60
+ case EAknSoftkeyExit: {
+ QCloseEvent ev;
+ QApplication::sendSpontaneousEvent(q, &ev);
+ if (ev.isAccepted()) {
+ q->quit();
+ ret = 1;
+ }
+ break;
+ }
+#endif
+ case EEikCmdExit:
+ q->quit();
+ ret = 1;
+ break;
+ default:
+#ifdef Q_WS_S60
+ bool handled = QSoftKeyManager::handleCommand(command);
+ if (handled)
+ ret = 1;
+ else
+ ret = QMenuBarPrivate::symbianCommands(command);
+#endif
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ \warning This function is only available on Symbian.
+ \since 4.6
+
+ Handles the resource change specified by \a type.
+
+ Currently, KEikDynamicLayoutVariantSwitch and
+ KAknsMessageSkinChange are handled.
+ */
+int QApplicationPrivate::symbianResourceChange(const QSymbianEvent *symbianEvent)
+{
+ int ret = 0;
+
+ int type = symbianEvent->resourceChangeType();
+
+ switch (type) {
+#ifdef Q_WS_S60
+ case KEikDynamicLayoutVariantSwitch:
+ {
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+ if (S60)
+ S60->updateScreenSize();
+
+#ifndef QT_NO_STYLE_S60
+ QS60Style *s60Style = 0;
+
+#ifndef QT_NO_STYLE_STYLESHEET
+ QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style());
+ if (proxy)
+ s60Style = qobject_cast<QS60Style*>(proxy->baseStyle());
+ else
+#endif
+ s60Style = qobject_cast<QS60Style*>(QApplication::style());
+
+ if (s60Style) {
+ s60Style->d_func()->handleDynamicLayoutVariantSwitch();
+ ret = 1;
+ }
+#endif
+ }
+ break;
+
+#ifndef QT_NO_STYLE_S60
+ case KAknsMessageSkinChange:
+ if (callSymbianEventFilters(symbianEvent))
+ return 1;
+ if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) {
+ s60Style->d_func()->handleSkinChange();
+ ret = 1;
+ }
+ break;
+#endif
+#endif // Q_WS_S60
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+#ifndef QT_NO_WHEELEVENT
+int QApplication::wheelScrollLines()
+{
+ return QApplicationPrivate::wheel_scroll_lines;
+}
+
+void QApplication::setWheelScrollLines(int n)
+{
+ QApplicationPrivate::wheel_scroll_lines = n;
+}
+#endif //QT_NO_WHEELEVENT
+
+bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */)
+{
+ // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect)
+ return false;
+}
+
+void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */)
+{
+ // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
+}
+
+TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym)
+{
+ if (!scanCode)
+ return keysym;
+
+ QApplicationPrivate *d = QApplicationPrivate::instance();
+
+ if (keysym) {
+ // If keysym is specified, cache it.
+ d->scanCodeCache.insert(scanCode, keysym);
+ return keysym;
+ } else {
+ // If not, retrieve the cached version.
+ return d->scanCodeCache[scanCode];
+ }
+}
+
+void QApplicationPrivate::initializeMultitouch_sys()
+{
+#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
+ if (HAL::Get(HALData::EPointer3DPressureSupported, pressureSupported) != KErrNone)
+ pressureSupported = 0;
+ if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone)
+ maxTouchPressure = KMaxTInt;
+#else
+ pressureSupported = 0;
+ maxTouchPressure = KMaxTInt;
+#endif
+}
+
+void QApplicationPrivate::cleanupMultitouch_sys()
+{ }
+
+#ifndef QT_NO_SESSIONMANAGER
+QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */)
+{
+
+}
+
+QSessionManager::~QSessionManager()
+{
+
+}
+
+bool QSessionManager::allowsInteraction()
+{
+ return false;
+}
+
+void QSessionManager::cancel()
+{
+
+}
+#endif //QT_NO_SESSIONMANAGER
+
+#ifdef QT_KEYPAD_NAVIGATION
+/*
+ * Show/Hide the mouse cursor depending on phone type and chosen mode
+ */
+void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode)
+{
+#ifndef QT_NO_CURSOR
+ const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto
+ && !S60->hasTouchscreen)
+ || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible;
+ const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto
+ && !S60->hasTouchscreen)
+ || mode == Qt::NavigationModeCursorForceVisible;
+
+ if (!wasCursorOn && isCursorOn) {
+ //Show the cursor, when changing from another mode to cursor mode
+ qt_symbian_set_cursor_visible(true);
+ }
+ else if (wasCursorOn && !isCursorOn) {
+ //Hide the cursor, when leaving cursor mode
+ qt_symbian_set_cursor_visible(false);
+ }
+#endif
+ QApplicationPrivate::navigationMode = mode;
+}
+#endif
+
+#ifndef QT_NO_CURSOR
+/*****************************************************************************
+ QApplication cursor stack
+ *****************************************************************************/
+
+void QApplication::setOverrideCursor(const QCursor &cursor)
+{
+ qApp->d_func()->cursor_list.prepend(cursor);
+ qt_symbian_setGlobalCursor(cursor);
+}
+
+void QApplication::restoreOverrideCursor()
+{
+ if (qApp->d_func()->cursor_list.isEmpty())
+ return;
+ qApp->d_func()->cursor_list.removeFirst();
+
+ if (!qApp->d_func()->cursor_list.isEmpty()) {
+ qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first());
+ }
+ else {
+ //determine which widget has focus
+ QWidget *w = QApplication::widgetAt(QCursor::pos());
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors) {
+ qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor);
+ }
+ else
+#endif
+ {
+ //because of the internals of window server, we need to force the cursor
+ //to be set in all child windows too, otherwise when the cursor is over
+ //the child window it may show a widget cursor or arrow cursor instead,
+ //depending on construction order.
+ QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys());
+ while (iter.hasNext()) {
+ CCoeControl *ctrl = iter.next();
+ if(ctrl->OwnsWindow()) {
+ ctrl->DrawableWindow()->ClearPointerCursor();
+ }
+ }
+ if (w)
+ qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId());
+ else
+ qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
+ }
+ }
+}
+
+#endif // QT_NO_CURSOR
+
+void QApplicationPrivate::_q_aboutToQuit()
+{
+ qt_beginFullScreenEffect();
+
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
+ // Send the shutdown tfx command
+ S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown);
+#endif
+}
+
+QS60ThreadLocalData::QS60ThreadLocalData()
+{
+ CCoeEnv *env = CCoeEnv::Static();
+ if (env) {
+ //if this is the UI thread, share objects owned by CONE
+ usingCONEinstances = true;
+ wsSession = env->WsSession();
+ screenDevice = env->ScreenDevice();
+ }
+ else {
+ usingCONEinstances = false;
+ qt_symbian_throwIfError(wsSession.Connect(qt_s60GetRFs()));
+ screenDevice = new CWsScreenDevice(wsSession);
+ screenDevice->Construct();
+ }
+}
+
+QS60ThreadLocalData::~QS60ThreadLocalData()
+{
+ if (!usingCONEinstances) {
+ delete screenDevice;
+ wsSession.Close();
+ }
+}
+
+QT_END_NAMESPACE