src/gui/kernel/qwidget.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
--- a/src/gui/kernel/qwidget.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/gui/kernel/qwidget.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)
 **
@@ -118,6 +118,10 @@
 #include "private/qgraphicssystem_p.h"
 #include "private/qgesturemanager_p.h"
 
+#ifdef QT_KEYPAD_NAVIGATION
+#include "qtabwidget.h" // Needed in inTabWidget()
+#endif // QT_KEYPAD_NAVIGATION
+
 // widget/widget data creation count
 //#define QWIDGET_EXTRA_DEBUG
 //#define ALIEN_DEBUG
@@ -192,6 +196,7 @@
       , inDirtyList(0)
       , isScrolled(0)
       , isMoved(0)
+      , isGLWidget(0)
       , usesDoubleBufferedGLContext(0)
 #if defined(Q_WS_X11)
       , picture(0)
@@ -200,7 +205,6 @@
       , nativeGesturePanEnabled(0)
 #elif defined(Q_WS_MAC)
       , needWindowChange(0)
-      , isGLWidget(0)
       , window_event(0)
       , qd_hd(0)
 #endif
@@ -1439,6 +1443,18 @@
     }
 #endif
 
+#ifdef Q_OS_SYMBIAN
+    if (d->extra && d->extra->topextra && d->extra->topextra->backingStore) {
+        // Okay, we are about to destroy the top-level window that owns
+        // the backing store. Make sure we delete the backing store right away
+        // before the window handle is invalid. This is important because
+        // the backing store will delete its window surface, which may or may
+        // not have a reference to this widget that will be used later to
+        // notify the window it no longer has a surface.
+        delete d->extra->topextra->backingStore;
+        d->extra->topextra->backingStore = 0;
+    }
+#endif
     if (QWidgetBackingStore *bs = d->maybeBackingStore()) {
         bs->removeDirtyWidget(this);
         if (testAttribute(Qt::WA_StaticContents))
@@ -1660,7 +1676,13 @@
         repaint_sys(dirty);
         dirty = QRegion();
     } else if (QWidgetBackingStore *bs = maybeBackingStore()) {
+#ifdef QT_MAC_USE_COCOA
+        Q_UNUSED(bs);
+        void qt_mac_set_needs_display(QWidget *, QRegion);
+        qt_mac_set_needs_display(q_func(), QRegion());
+#else
         bs->sync();
+#endif
     }
 }
 
@@ -1668,8 +1690,15 @@
 {
     if (paintOnScreen())
         repaint_sys(region);
-    else if (QWidgetBackingStore *bs = maybeBackingStore())
+    else if (QWidgetBackingStore *bs = maybeBackingStore()) {
+#ifdef QT_MAC_USE_COCOA
+        Q_UNUSED(bs);
+        void qt_mac_set_needs_display(QWidget *, QRegion);
+        qt_mac_set_needs_display(q_func(), region);
+#else
         bs->sync(q_func(), region);
+#endif
+    }
 }
 
 void QWidgetPrivate::setUpdatesEnabled_helper(bool enable)
@@ -2026,6 +2055,14 @@
     }
 #endif
 
+#ifdef Q_WS_S60
+    if (q->windowType() == Qt::Dialog && q->testAttribute(Qt::WA_TranslucentBackground)
+                && S60->avkonComponentsSupportTransparency) {
+        setOpaque(false);
+        return;
+    }
+#endif
+
     if (q->testAttribute(Qt::WA_OpaquePaintEvent) || q->testAttribute(Qt::WA_PaintOnScreen)) {
         setOpaque(true);
         return;
@@ -3088,7 +3125,8 @@
         QWidget *focusWidget = effectiveFocusWidget();
         QInputContext *qic = focusWidget->d_func()->inputContext();
         if (enable) {
-            qic->setFocusWidget(focusWidget);
+            if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled))
+                qic->setFocusWidget(focusWidget);
         } else {
             qic->reset();
             qic->setFocusWidget(0);
@@ -3343,7 +3381,7 @@
     \note Setting the size to \c{QSize(0, 0)} will cause the widget to not
     appear on screen. This also applies to windows.
 
-    \sa pos, geometry, minimumSize, maximumSize, resizeEvent()
+    \sa pos, geometry, minimumSize, maximumSize, resizeEvent(), adjustSize()
 */
 
 /*!
@@ -6085,6 +6123,8 @@
             previousProxyFocus = topData->proxyWidget->widget()->focusWidget();
             if (previousProxyFocus && previousProxyFocus->focusProxy())
                 previousProxyFocus = previousProxyFocus->focusProxy();
+            if (previousProxyFocus == this && !topData->proxyWidget->d_func()->proxyIsGivingFocus)
+                return;
         }
     }
 #endif
@@ -6405,6 +6445,8 @@
         first = fp;
     }
 
+    if (fp == second)
+        return;
 
     if (QWidget *sp = second->focusProxy())
         second = sp;
@@ -7495,6 +7537,23 @@
         QWidget *widget = qobject_cast<QWidget*>(childList.at(i));
         if (!widget || widget->isWindow() || widget->testAttribute(Qt::WA_WState_Hidden))
             continue;
+#ifdef QT_MAC_USE_COCOA
+        // Before doing anything we need to make sure that we don't leave anything in a non-consistent state.
+        // When hiding a widget we need to make sure that no mouse_down events are active, because
+        // the mouse_up event will never be received by a hidden widget or one of its descendants.
+        // The solution is simple, before going through with this we check if there are any mouse_down events in
+        // progress, if so we check if it is related to this widget or not. If so, we just reset the mouse_down and
+        // then we continue.
+        // In X11 and Windows we send a mouse_release event, however we don't do that here because we were already
+        // ignoring that from before. I.e. Carbon did not send the mouse release event, so we will not send the
+        // mouse release event. There are two ways to interpret this:
+        // 1. If we don't send the mouse release event, the widget might get into an inconsistent state, i.e. it
+        // might be waiting for a release event that will never arrive.
+        // 2. If we send the mouse release event, then the widget might decide to trigger an action that is not
+        // supposed to trigger because it is not visible.
+        if(widget == qt_button_down)
+            qt_button_down = 0;
+#endif // QT_MAC_USE_COCOA
         if (spontaneous)
             widget->setAttribute(Qt::WA_Mapped, false);
         else
@@ -7889,13 +7948,16 @@
     // set/reset WS_DISABLED style.
     if(w && w->isWindow() && w->isVisible() && w->isEnabled()) {
         LONG dwStyle = GetWindowLong(w->winId(), GWL_STYLE);
+        LONG newStyle = dwStyle;
         if (setStyle)
-            dwStyle |= WS_DISABLED;
+            newStyle |= WS_DISABLED;
         else
-            dwStyle &= ~WS_DISABLED;
-        SetWindowLong(w->winId(), GWL_STYLE, dwStyle);
-        // we might need to repaint in some situations (eg. menu)
-        w->repaint();
+            newStyle &= ~WS_DISABLED;
+        if (newStyle != dwStyle) {
+            SetWindowLong(w->winId(), GWL_STYLE, newStyle);
+            // we might need to repaint in some situations (eg. menu)
+            w->repaint();
+        }
     }
 }
 #endif
@@ -8235,7 +8297,7 @@
         }
 
 #ifdef QT_SOFTKEYS_ENABLED
-        if (isWindow() && isActiveWindow())
+        if (isWindow())
             QSoftKeyManager::updateSoftKeys();
 #endif
 
@@ -9774,13 +9836,12 @@
     }
 #endif
 
-    if (newParent) {
-        if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) {
+    if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) {
+        if (newParent)
             oldBs->removeDirtyWidget(this);
-            // Move the widget and all its static children from
-            // the old backing store to the new one.
-            oldBs->moveStaticWidgets(this);
-        }
+        // Move the widget and all its static children from
+        // the old backing store to the new one.
+        oldBs->moveStaticWidgets(this);
     }
 
     if ((QApplicationPrivate::app_compile_version < 0x040200
@@ -10358,17 +10419,22 @@
 #ifndef QT_NO_IM
         QWidget *focusWidget = d->effectiveFocusWidget();
         QInputContext *ic = 0;
-        if (on && !internalWinId() && testAttribute(Qt::WA_InputMethodEnabled) && hasFocus()) {
+        if (on && !internalWinId() && hasFocus()
+            && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) {
             ic = focusWidget->d_func()->inputContext();
-            ic->reset();
-            ic->setFocusWidget(0);
+            if (ic) {
+                ic->reset();
+                ic->setFocusWidget(0);
+            }
         }
         if (!qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) && parentWidget())
             parentWidget()->d_func()->enforceNativeChildren();
         if (on && !internalWinId() && testAttribute(Qt::WA_WState_Created))
             d->createWinId();
-        if (ic && isEnabled())
+        if (ic && isEnabled() && focusWidget->isEnabled()
+            && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) {
             ic->setFocusWidget(focusWidget);
+        }
 #endif //QT_NO_IM
         break;
     }
@@ -10405,7 +10471,8 @@
         if (!ic && (!on || hasFocus()))
             ic = focusWidget->d_func()->inputContext();
         if (ic) {
-            if (on && hasFocus() && ic->focusWidget() != focusWidget && isEnabled()) {
+            if (on && hasFocus() && ic->focusWidget() != focusWidget && isEnabled()
+                && focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) {
                 ic->setFocusWidget(focusWidget);
             } else if (!on && ic->focusWidget() == focusWidget) {
                 ic->reset();
@@ -11585,6 +11652,45 @@
     }
     return targetWidget;
 }
+
+/*!
+    \internal
+
+    Tells us if it there is currently a reachable widget by keypad navigation in
+    a certain \a orientation.
+    If no navigation is possible, occuring key events in that \a orientation may
+    be used to interact with the value in the focussed widget, even though it
+    currently has not the editFocus.
+
+    \sa QWidgetPrivate::widgetInNavigationDirection(), QWidget::hasEditFocus()
+*/
+bool QWidgetPrivate::canKeypadNavigate(Qt::Orientation orientation)
+{
+    return orientation == Qt::Horizontal?
+            (QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionEast)
+                    || QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionWest))
+            :(QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionNorth)
+                    || QWidgetPrivate::widgetInNavigationDirection(QWidgetPrivate::DirectionSouth));
+}
+/*!
+    \internal
+
+    Checks, if the \a widget is inside a QTabWidget. If is is inside
+    one, left/right key events will be used to switch between tabs in keypad
+    navigation. If there is no QTabWidget, the horizontal key events can be used
+to
+    interact with the value in the focussed widget, even though it currently has
+    not the editFocus.
+
+    \sa QWidget::hasEditFocus()
+*/
+bool QWidgetPrivate::inTabWidget(QWidget *widget)
+{
+    for (QWidget *tabWidget = widget; tabWidget; tabWidget = tabWidget->parentWidget())
+        if (qobject_cast<const QTabWidget*>(tabWidget))
+            return true;
+    return false;
+}
 #endif
 
 /*!
@@ -11872,16 +11978,20 @@
     mouse when a mouse button is pressed and keeps it until the last
     button is released.
 
-    Note that only visible widgets can grab mouse input. If
-    isVisible() returns false for a widget, that widget cannot call
-    grabMouse().
+    \note Only visible widgets can grab mouse input. If isVisible()
+    returns false for a widget, that widget cannot call grabMouse().
+
+    \note \bold{(Mac OS X developers)} For \e Cocoa, calling
+    grabMouse() on a widget only works when the mouse is inside the
+    frame of that widget.  For \e Carbon, it works outside the widget's
+    frame as well, like for Windows and X11.
 
     \sa releaseMouse() grabKeyboard() releaseKeyboard()
 */
 
 /*!
     \fn void QWidget::grabMouse(const QCursor &cursor)
-    \overload
+    \overload grabMouse()
 
     Grabs the mouse input and changes the cursor shape.
 
@@ -11891,6 +12001,8 @@
 
     \warning Grabbing the mouse might lock the terminal.
 
+    \note \bold{(Mac OS X developers)} See the note in QWidget::grabMouse().
+
     \sa releaseMouse(), grabKeyboard(), releaseKeyboard(), setCursor()
 */