summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGareth Stockwell <ext-gareth.stockwell@nokia.com>2010-10-19 15:46:18 (GMT)
committerGareth Stockwell <ext-gareth.stockwell@nokia.com>2010-10-26 13:22:59 (GMT)
commitf417a6e7729a506e5a59e7fd38e03166515198b1 (patch)
tree090d140dde5a47d0e11428c809b496ca48dc767a
parent586fc2a9ead06a8478bdc380b775f18000741745 (diff)
downloadQt-f417a6e7729a506e5a59e7fd38e03166515198b1.zip
Qt-f417a6e7729a506e5a59e7fd38e03166515198b1.tar.gz
Qt-f417a6e7729a506e5a59e7fd38e03166515198b1.tar.bz2
Remove widget subtree from backing store tracker when reparented
When a native widget is reparented such that the value of maybeBackingStore() changes, it and all of its native descendents must be removed from the old QWidgetBackingStoreTracker. If this is not done, the backing store may not be deleted when the top-level widget is hidden, thereby consuming memory unnecessarily. Task-number: MOBILITY-1315 Reviewed-by: Jason Barron Reviewed-by: bnilsen
-rw-r--r--src/gui/kernel/qwidget.cpp20
-rw-r--r--src/gui/kernel/qwidget_p.h1
-rw-r--r--tests/auto/qwidget/tst_qwidget.cpp24
3 files changed, 42 insertions, 3 deletions
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 9b44f15..6c64ffc 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -236,6 +236,17 @@ void QWidgetBackingStoreTracker::unregisterWidget(QWidget *w)
}
}
+/*!
+ \internal
+ Recursively remove widget and all of its descendents.
+ */
+void QWidgetBackingStoreTracker::unregisterWidgetSubtree(QWidget *widget)
+{
+ unregisterWidget(widget);
+ foreach (QObject *child, widget->children())
+ if (QWidget *childWidget = qobject_cast<QWidget *>(child))
+ unregisterWidgetSubtree(childWidget);
+}
QWidgetPrivate::QWidgetPrivate(int version)
: QObjectPrivate(version)
@@ -10031,7 +10042,16 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
if (newParent && isAncestorOf(focusWidget()))
focusWidget()->clearFocus();
+ QTLWExtra *oldTopExtra = window()->d_func()->maybeTopData();
+ QWidgetBackingStoreTracker *oldBsTracker = oldTopExtra ? &oldTopExtra->backingStore : 0;
+
d->setParent_sys(parent, f);
+
+ QTLWExtra *topExtra = window()->d_func()->maybeTopData();
+ QWidgetBackingStoreTracker *bsTracker = topExtra ? &topExtra->backingStore : 0;
+ if (oldBsTracker && oldBsTracker != bsTracker)
+ oldBsTracker->unregisterWidgetSubtree(this);
+
if (desktopWidget)
parent = 0;
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index 6c89659..ca1e3fc 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -122,6 +122,7 @@ public:
void registerWidget(QWidget *w);
void unregisterWidget(QWidget *w);
+ void unregisterWidgetSubtree(QWidget *w);
inline QWidgetBackingStore* data()
{
diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp
index 2f221d2..09af941 100644
--- a/tests/auto/qwidget/tst_qwidget.cpp
+++ b/tests/auto/qwidget/tst_qwidget.cpp
@@ -9718,14 +9718,25 @@ void tst_QWidget::destroyBackingStoreWhenHidden()
child.setAutoFillBackground(true);
child.setPalette(Qt::blue);
+ QWidget grandChild(&child);
+ grandChild.setAutoFillBackground(true);
+ grandChild.setPalette(Qt::yellow);
+
QVBoxLayout layout(&parent);
layout.setContentsMargins(10, 10, 10, 10);
layout.addWidget(&child);
parent.setLayout(&layout);
- child.winId();
+ QVBoxLayout childLayout(&child);
+ childLayout.setContentsMargins(10, 10, 10, 10);
+ childLayout.addWidget(&grandChild);
+ child.setLayout(&childLayout);
+
+ // Ensure that this widget and all its ancestors are native
+ grandChild.winId();
parent.show();
+
QTest::qWaitForWindowShown(&parent);
// Check that child window does not obscure parent window
@@ -9734,18 +9745,24 @@ void tst_QWidget::destroyBackingStoreWhenHidden()
// Native child widget should share parent's backing store
QVERIFY(0 != backingStore(parent));
QVERIFY(0 == backingStore(child));
+ QVERIFY(0 == backingStore(grandChild));
// Make child widget full screen
child.setWindowFlags((child.windowFlags() | Qt::Window) ^ Qt::SubWindow);
child.setWindowState(child.windowState() | Qt::WindowFullScreen);
child.show();
+
+ // Paint into the child to ensure that it gets a backing store
+ QPainter painter(&child);
+ painter.fillRect(QRect(0, 0, 90, 90), Qt::white);
+
QTest::qWaitForWindowShown(&child);
// Ensure that 'window hidden' event is received by parent
qApp->processEvents();
// Check that child window obscures parent window
- QVERIFY(parent.visibleRegion().subtracted(child.visibleRegion()).isEmpty());
+ QVERIFY(parent.visibleRegion().subtracted(child.visibleRegion() + grandChild.visibleRegion()).isEmpty());
// Now that extent of child widget goes beyond parent's extent,
// a new backing store should be created for the child widget.
@@ -9761,11 +9778,12 @@ void tst_QWidget::destroyBackingStoreWhenHidden()
QTest::qWaitForWindowShown(&child);
// Check that parent is now visible again
- QVERIFY(!parent.visibleRegion().subtracted(child.visibleRegion()).isEmpty());
+ QVERIFY(!parent.visibleRegion().subtracted(child.visibleRegion() + grandChild.visibleRegion()).isEmpty());
// Native child widget should once again share parent's backing store
QVERIFY(0 != backingStore(parent));
QVERIFY(0 == backingStore(child));
+ QVERIFY(0 == backingStore(grandChild));
}
// 6. Partial reveal followed by full reveal