src/gui/kernel/qwidget.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
--- a/src/gui/kernel/qwidget.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/gui/kernel/qwidget.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -67,6 +67,7 @@
 # include "qt_mac_p.h"
 # include "qt_cocoa_helpers_mac_p.h"
 # include "qmainwindow.h"
+# include "qtoolbar.h"
 #endif
 #if defined(Q_WS_QWS)
 # include "qwsdisplay_qws.h"
@@ -161,6 +162,47 @@
 extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp
 extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
 
+QRefCountedWidgetBackingStore::QRefCountedWidgetBackingStore()
+    :   m_ptr(0)
+{
+
+}
+
+QRefCountedWidgetBackingStore::~QRefCountedWidgetBackingStore()
+{
+    delete m_ptr;
+}
+
+void QRefCountedWidgetBackingStore::create(QWidget *widget)
+{
+    destroy();
+    m_ptr = new QWidgetBackingStore(widget);
+}
+
+void QRefCountedWidgetBackingStore::destroy()
+{
+    delete m_ptr;
+    m_ptr = 0;
+    m_visibleWidgets.clear();
+}
+
+void QRefCountedWidgetBackingStore::widgetShown(QWidget *w)
+{
+    Q_ASSERT(m_ptr);
+    Q_ASSERT(w->internalWinId());
+    Q_ASSERT(qt_widget_private(w)->maybeBackingStore() == m_ptr);
+    m_visibleWidgets.insert(w);
+}
+
+void QRefCountedWidgetBackingStore::widgetHidden(QWidget *w)
+{
+    if (m_visibleWidgets.remove(w) && m_visibleWidgets.isEmpty()) {
+        delete m_ptr;
+        m_ptr = 0;
+    }
+}
+
+
 QWidgetPrivate::QWidgetPrivate(int version)
     : QObjectPrivate(version)
       , extra(0)
@@ -202,7 +244,9 @@
       , picture(0)
 #elif defined(Q_WS_WIN)
       , noPaintOnScreen(0)
+  #ifndef QT_NO_GESTURES
       , nativeGesturePanEnabled(0)
+  #endif
 #elif defined(Q_WS_MAC)
       , needWindowChange(0)
       , hasAlienChildren(0)
@@ -248,9 +292,14 @@
 QWindowSurface *QWidgetPrivate::createDefaultWindowSurface()
 {
     Q_Q(QWidget);
+
+    QWindowSurface *surface;
     if (QApplicationPrivate::graphicsSystem())
-        return QApplicationPrivate::graphicsSystem()->createWindowSurface(q);
-    return createDefaultWindowSurface_sys();
+        surface = QApplicationPrivate::graphicsSystem()->createWindowSurface(q);
+    else
+        surface = createDefaultWindowSurface_sys();
+
+    return surface;
 }
 
 /*!
@@ -285,8 +334,10 @@
 #ifndef QT_NO_IM
     if (ic)
         return ic;
-#endif
     return qApp->inputContext();
+#else
+    return 0;
+#endif
 }
 
 /*!
@@ -312,6 +363,8 @@
   This function sets the input context \a context
   on this widget.
 
+  Qt takes ownership of the given input \a context.
+
   \sa inputContext()
 */
 void QWidget::setInputContext(QInputContext *context)
@@ -320,9 +373,13 @@
     if (!testAttribute(Qt::WA_InputMethodEnabled))
         return;
 #ifndef QT_NO_IM
+    if (context == d->ic)
+        return;
     if (d->ic)
         delete d->ic;
     d->ic = context;
+    if (d->ic)
+        d->ic->setParent(this);
 #endif
 }
 
@@ -670,8 +727,8 @@
     (to move the keyboard focus), and passes on most of the other events to
     one of the more specialized handlers above.
 
-    Events and the mechanism used to deliver them are covered in the
-    \l{Events and Event Filters} document.
+    Events and the mechanism used to deliver them are covered in 
+    \l{The Event System}.
 
     \section1 Groups of Functions and Properties
 
@@ -1010,7 +1067,6 @@
 
     \sa windowFlags
 */
-
 QWidget::QWidget(QWidget *parent, Qt::WindowFlags f)
     : QObject(*new QWidgetPrivate, 0), QPaintDevice()
 {
@@ -1339,11 +1395,9 @@
 
     // a real toplevel window needs a backing store
     if (isWindow() && windowType() != Qt::Desktop) {
-        delete d->topData()->backingStore;
-        // QWidgetBackingStore will check this variable, hence it must be 0
-        d->topData()->backingStore = 0;
+        d->topData()->backingStore.destroy();
         if (hasBackingStoreSupport())
-            d->topData()->backingStore = new QWidgetBackingStore(this);
+            d->topData()->backingStore.create(this);
     }
 
     d->setModal_sys();
@@ -1388,8 +1442,10 @@
         qWarning("QWidget: %s (%s) deleted while being painted", className(), name());
 #endif
 
+#ifndef QT_NO_GESTURES
     foreach (Qt::GestureType type, d->gestureContext.keys())
         ungrabGesture(type);
+#endif
 
     // force acceptDrops false before winId is destroyed.
     d->registerDropSite(false);
@@ -1469,8 +1525,7 @@
         // 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;
+        d->extra->topextra->backingStore.destroy();
     }
 #endif
     if (QWidgetBackingStore *bs = d->maybeBackingStore()) {
@@ -1567,7 +1622,6 @@
         QTLWExtra* x = extra->topextra = new QTLWExtra;
         x->icon = 0;
         x->iconPixmap = 0;
-        x->backingStore = 0;
         x->windowSurface = 0;
         x->sharedPainter = 0;
         x->incw = x->inch = 0;
@@ -1651,7 +1705,7 @@
 #endif
         if (extra->topextra) {
             deleteTLSysExtra();
-            delete extra->topextra->backingStore;
+            extra->topextra->backingStore.destroy();
             delete extra->topextra->icon;
             delete extra->topextra->iconPixmap;
 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER)
@@ -4774,6 +4828,11 @@
 {
     Q_D(QWidget);
 
+    if (direction == Qt::LayoutDirectionAuto) {
+        unsetLayoutDirection();
+        return;
+    }
+
     setAttribute(Qt::WA_SetLayoutDirection);
     d->setLayoutDirection_helper(direction);
 }
@@ -8530,9 +8589,11 @@
 #endif // Q_WS_MAC
         break;
     }
+#ifndef QT_NO_GESTURES
     case QEvent::Gesture:
         event->ignore();
         break;
+#endif
 #ifndef QT_NO_PROPERTIES
     case QEvent::DynamicPropertyChange: {
         const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
@@ -9655,46 +9716,58 @@
 
 QWidget *QWidgetPrivate::childAt_helper(const QPoint &p, bool ignoreChildrenInDestructor) const
 {
+    if (children.isEmpty())
+        return 0;
+
+#ifdef Q_WS_MAC
     Q_Q(const QWidget);
-#ifdef Q_WS_MAC
+    // Unified tool bars on the Mac require special handling since they live outside
+    // QMainWindow's geometry(). See commit: 35667fd45ada49269a5987c235fdedfc43e92bb8
     bool includeFrame = q->isWindow() && qobject_cast<const QMainWindow *>(q)
                         && static_cast<const QMainWindow *>(q)->unifiedTitleAndToolBarOnMac();
-#endif
-
-    if (
-#ifdef Q_WS_MAC
-            !includeFrame &&
-#endif
-            !q->rect().contains(p))
+    if (includeFrame)
+        return childAtRecursiveHelper(p, ignoreChildrenInDestructor, includeFrame);
+#endif
+
+    if (!pointInsideRectAndMask(p))
         return 0;
-
-    for (int i = children.size(); i > 0 ;) {
-        --i;
-        QWidget *w = qobject_cast<QWidget *>(children.at(i));
-        if (w && !w->isWindow() && !w->isHidden()
-                && (w->geometry().contains(p)
+    return childAtRecursiveHelper(p, ignoreChildrenInDestructor);
+}
+
+QWidget *QWidgetPrivate::childAtRecursiveHelper(const QPoint &p, bool ignoreChildrenInDestructor, bool includeFrame) const
+{
+#ifndef Q_WS_MAC
+    Q_UNUSED(includeFrame);
+#endif
+    for (int i = children.size() - 1; i >= 0; --i) {
+        QWidget *child = qobject_cast<QWidget *>(children.at(i));
+        if (!child || child->isWindow() || child->isHidden() || child->testAttribute(Qt::WA_TransparentForMouseEvents)
+            || (ignoreChildrenInDestructor && child->data->in_destructor)) {
+            continue;
+        }
+
+        // Map the point 'p' from parent coordinates to child coordinates.
+        QPoint childPoint = p;
 #ifdef Q_WS_MAC
-                    || (includeFrame && w->geometry().contains(qt_mac_nativeMapFromParent(w, p)))
-#endif
-               )) {
-            if (ignoreChildrenInDestructor && w->data->in_destructor)
-                continue;
-            if (w->testAttribute(Qt::WA_TransparentForMouseEvents))
-                continue;
-            QPoint childPoint = w->mapFromParent(p);
-#ifdef Q_WS_MAC
-            if (includeFrame && !w->geometry().contains(p))
-                childPoint = qt_mac_nativeMapFromParent(w, p);
-#endif
-            if (QWidget *t = w->d_func()->childAt_helper(childPoint, ignoreChildrenInDestructor))
-                return t;
-            // if WMouseNoMask is set the widget mask is ignored, if
-            // the widget has no mask then the WMouseNoMask flag has no
-            // effect
-            if (w->testAttribute(Qt::WA_MouseNoMask) || w->mask().contains(childPoint)
-                || w->mask().isEmpty())
-                return w;
-        }
+        // 'includeFrame' is true if the child's parent is a top-level QMainWindow with an unified tool bar.
+        // An unified tool bar on the Mac lives outside QMainWindow's geometry(), so a normal
+        // QWidget::mapFromParent won't do the trick.
+        if (includeFrame && qobject_cast<QToolBar *>(child))
+            childPoint = qt_mac_nativeMapFromParent(child, p);
+        else
+#endif
+        childPoint -= child->data->crect.topLeft();
+
+        // Check if the point hits the child.
+        if (!child->d_func()->pointInsideRectAndMask(childPoint))
+            continue;
+
+        // Do the same for the child's descendants.
+        if (QWidget *w = child->d_func()->childAtRecursiveHelper(childPoint, ignoreChildrenInDestructor))
+            return w;
+
+        // We have found our target; namely the child at position 'p'.
+        return child;
     }
     return 0;
 }
@@ -10620,7 +10693,7 @@
 
         break;
     case Qt::WA_AcceptTouchEvents:
-#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60)
+#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN)
         if (on)
             d->registerTouchWindow();
 #endif
@@ -11948,6 +12021,7 @@
     Synonym for QList<QWidget *>.
 */
 
+#ifndef QT_NO_GESTURES
 /*!
     Subscribes the widget to a given \a gesture with specific \a flags.
 
@@ -11975,7 +12049,7 @@
         manager->cleanupCachedGestures(this, gesture);
     }
 }
-
+#endif // QT_NO_GESTURES
 
 /*!
     \typedef WId