src/gui/kernel/qapplication_s60.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
--- a/src/gui/kernel/qapplication_s60.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/gui/kernel/qapplication_s60.cpp	Wed Mar 31 11:06:36 2010 +0300
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -52,6 +52,7 @@
 #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
@@ -71,6 +72,7 @@
 #  include <private/qcoefepinputcontext_p.h>
 # endif
 # include <private/qs60mainapplication_p.h>
+# include <centralrepository.h>
 #endif
 
 #include "private/qstylesheetstyle_p.h"
@@ -596,7 +598,9 @@
         TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode,
                 keyEvent.iCode);
         int keyCode;
-        if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) {
+        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 {
@@ -807,6 +811,18 @@
 
 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);
+    if (!topExtra->inExpose) {
+        topExtra->inExpose = true;
+        QRect exposeRect = qt_TRect2QRect(controlRect);
+        qwidget->d_func()->syncBackingStore(exposeRect);
+        topExtra->inExpose = false;
+    }
+
     QWindowSurface *surface = qwidget->windowSurface();
     QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL;
 
@@ -855,8 +871,6 @@
         default:
             Q_ASSERT(false);
         }
-    } else {
-        surface->flush(qwidget, QRegion(qt_TRect2QRect(backingStoreRect)), QPoint());
     }
 
     if (sendNativePaintEvents) {
@@ -916,8 +930,8 @@
         cr.moveTopLeft(newPos);
         qwidget->data->crect = cr;
         QTLWExtra *top = qwidget->d_func()->maybeTopData();
-        if (top)
-            top->normalGeometry = cr;
+        if (top && (qwidget->windowState() & (~Qt::WindowActive)) == Qt::WindowNoState)
+            top->normalGeometry.moveTopLeft(newPos);
         if (qwidget->isVisible()) {
             QMoveEvent e(newPos, oldPos);
             qt_sendSpontaneousEvent(qwidget, &e);
@@ -930,7 +944,7 @@
 
 void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
 {
-    if (m_ignoreFocusChanged)
+    if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
         return;
 
     // Popups never get focused, but still receive the FocusChanged when they are hidden.
@@ -952,15 +966,27 @@
         qwidget->d_func()->setWindowIcon_sys(true);
         qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
 #ifdef Q_WS_S60
-        // If widget is fullscreen, hide status pane and button container
-        // otherwise show them.
-        CEikStatusPane* statusPane = S60->statusPane();
-        CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer();
-        bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
-        if (statusPane && (bool)statusPane->IsVisible() == isFullscreen)
-            statusPane->MakeVisible(!isFullscreen);
-        if (buttonGroup && (bool)buttonGroup->IsVisible() == isFullscreen)
-            buttonGroup->MakeVisible(!isFullscreen);
+        // If widget is fullscreen/minimized, hide status pane and button container otherwise show them.
+        CEikStatusPane *statusPane = S60->statusPane();
+        CEikButtonGroupContainer *buttonGroup = S60->buttonGroupContainer();
+        TBool visible = !(qwidget->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized));
+        if (statusPane)
+            statusPane->MakeVisible(visible);
+        if (buttonGroup) {
+            // Visibility
+            const TBool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
+            const TBool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
+            buttonGroup->MakeVisible(visible || (isFullscreen && cbaVisibilityHint));
+
+            // Responsiviness
+            CEikCba *cba = static_cast<CEikCba *>( buttonGroup->ButtonGroup() ); // downcast from MEikButtonGroup
+            TUint cbaFlags = cba->ButtonGroupFlags();
+            if(qwidget->windowFlags() & Qt::WindowSoftkeysRespondHint)
+                cbaFlags |= EAknCBAFlagRespondWhenInvisible;
+            else
+                cbaFlags &= ~EAknCBAFlagRespondWhenInvisible;
+            cba->SetButtonGroupFlags(cbaFlags);
+        }
 #endif
     } else if (QApplication::activeWindow() == qwidget->window()) {
         if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog()) {
@@ -978,16 +1004,32 @@
     // 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
+        }
+    }
+}
+
 void QSymbianControl::HandleResourceChange(int resourceType)
 {
     switch (resourceType) {
     case KInternalStatusPaneChange:
-        if (qwidget->isFullScreen()) {
-            SetExtentToWholeScreen();
-        } else if (qwidget->isMaximized()) {
-            TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
-            SetExtent(r.iTl, r.Size());
-        }
+        handleClientAreaChange();
         if (IsFocused() && IsVisible()) {
             qwidget->d_func()->setWindowIcon_sys(true);
             qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
@@ -999,12 +1041,7 @@
 #ifdef Q_WS_S60
     case KEikDynamicLayoutVariantSwitch:
     {
-        if (qwidget->isFullScreen()) {
-            SetExtentToWholeScreen();
-        } else if (qwidget->isMaximized()) {
-            TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
-            SetExtent(r.iTl, r.Size());
-        }
+        handleClientAreaChange();
         break;
     }
 #endif
@@ -1136,6 +1173,10 @@
 #endif
         S60->wsSession().SetAutoFlush(ETrue);
 
+#ifdef Q_SYMBIAN_WINDOW_SIZE_CACHE
+    TRAP_IGNORE(S60->wsSession().EnableWindowSizeCacheL());
+#endif
+
     S60->updateScreenSize();
 
 
@@ -1197,6 +1238,24 @@
         S60->virtualMouseRequired = false;
     }
 
+    S60->avkonComponentsSupportTransparency = 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;
+        }
+    }
+#endif
+
     if (touch) {
         QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
     } else {
@@ -1350,11 +1409,13 @@
 
 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();
@@ -1393,6 +1454,9 @@
 
 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);
@@ -1416,6 +1480,9 @@
         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 {
@@ -1521,6 +1588,12 @@
         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
@@ -1537,6 +1610,9 @@
 
     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();
@@ -1549,29 +1625,34 @@
 
     switch (event->type()) {
     case QSymbianEvent::WindowServerEvent:
-        return d->symbianProcessWsEvent(event->windowServerEvent());
+        return d->symbianProcessWsEvent(event);
     case QSymbianEvent::CommandEvent:
-        return d->symbianHandleCommand(event->command());
+        return d->symbianHandleCommand(event);
     case QSymbianEvent::ResourceChangeEvent:
-        return d->symbianResourceChange(event->resourceChangeType());
+        return d->symbianResourceChange(event);
     default:
         return -1;
     }
 }
 
-int QApplicationPrivate::symbianProcessWsEvent(const TWsEvent *event)
+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)
+        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,
@@ -1584,6 +1665,8 @@
         }
         break;
     case EEventScreenDeviceChanged:
+        if (callSymbianEventFilters(symbianEvent))
+            return 1;
         if (S60)
             S60->updateScreenSize();
         if (qt_desktopWidget) {
@@ -1596,6 +1679,8 @@
         return 0; // Propagate to CONE
     case EEventWindowVisibilityChanged:
         if (controlInMap) {
+            if (callSymbianEventFilters(symbianEvent))
+                return 1;
             const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
             QWidget *w = QWidgetPrivate::mapper->value(control);
             if (!w->d_func()->maybeTopData())
@@ -1603,9 +1688,9 @@
             if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) {
                 delete w->d_func()->topData()->backingStore;
                 w->d_func()->topData()->backingStore = 0;
-                // :QTP:QT-2506:remove this when QT-2506 is fixed
-                if (S60)
-                    S60->wsSession().Flush();
+                // In order to ensure that any resources used by the window surface
+                // are immediately freed, we flush the WSERV command buffer.
+                S60->wsSession().Flush();
             } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
                        && !w->d_func()->maybeBackingStore()) {
                 w->d_func()->topData()->backingStore = new QWidgetBackingStore(w);
@@ -1616,6 +1701,8 @@
         }
         break;
     case EEventFocusGained:
+        if (callSymbianEventFilters(symbianEvent))
+            return 1;
 #ifndef QT_NO_CURSOR
         //re-enable mouse interaction
         if (S60->mouseInteractionEnabled) {
@@ -1629,6 +1716,8 @@
 #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) {
@@ -1680,11 +1769,16 @@
 
   \sa s60EventFilter(), s60ProcessEvent()
 */
-int QApplicationPrivate::symbianHandleCommand(int command)
+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: {
@@ -1724,14 +1818,18 @@
   Currently, KEikDynamicLayoutVariantSwitch and
   KAknsMessageSkinChange are handled.
  */
-int QApplicationPrivate::symbianResourceChange(int type)
+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();
 
@@ -1756,6 +1854,8 @@
 
 #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;