diff options
author | Gareth Stockwell <ext-gareth.stockwell@nokia.com> | 2011-08-11 12:58:23 (GMT) |
---|---|---|
committer | Gareth Stockwell <ext-gareth.stockwell@nokia.com> | 2011-08-31 09:17:34 (GMT) |
commit | 298d7a2032c0c6de06c82afc8e9f7356cb5d7840 (patch) | |
tree | b7dc09a7f0934920c6d03c8e2f383347b464f6d9 /src/gui/kernel | |
parent | 91096126440aafba22aeb9307cb72135b3156a4c (diff) | |
download | Qt-298d7a2032c0c6de06c82afc8e9f7356cb5d7840.zip Qt-298d7a2032c0c6de06c82afc8e9f7356cb5d7840.tar.gz Qt-298d7a2032c0c6de06c82afc8e9f7356cb5d7840.tar.bz2 |
Prevent leakage of native window handles
On Symbian, reparenting a native widget causes its native window,
and those of all its ancestors, to be destroyed and recreated.
Because native window handles cannot be destroyed from the context
of CONE event handlers, the destruction is delayed until after
control flow returns to the event loop (see QTBUG-4664).
However, the pending-destruction native windows are leaked if
either of the following happens:
a) The application never returns to the event loop. While unlikely
in a real app, this situation does happen in Qt autotests, causing
a crash in tst_qwidget due to leakage from
tst_QWidget::reparentCausesChildWinIdChange().
b) A subsequent reparenting event occurs before control returns to
the event loop.
This patch prevents the leak by storing the pending-destruction
native window handle(s) in a member QList, rather than on the stack
as parameters to QWidgetPrivate::_q_delayedDestroy(WId).
Task-number: QT-5135
Reviewed-by: Jani Hautakangas
Diffstat (limited to 'src/gui/kernel')
-rw-r--r-- | src/gui/kernel/qwidget.cpp | 10 | ||||
-rw-r--r-- | src/gui/kernel/qwidget.h | 2 | ||||
-rw-r--r-- | src/gui/kernel/qwidget_p.h | 3 | ||||
-rw-r--r-- | src/gui/kernel/qwidget_s60.cpp | 8 |
4 files changed, 14 insertions, 9 deletions
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index ac8e690..8e8266c 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -334,6 +334,10 @@ QWidgetPrivate::QWidgetPrivate(int version) QWidgetPrivate::~QWidgetPrivate() { +#ifdef Q_OS_SYMBIAN + _q_cleanupWinIds(); +#endif + if (widgetItem) widgetItem->wid = 0; @@ -12561,9 +12565,11 @@ void QWidget::clearMask() */ #ifdef Q_OS_SYMBIAN -void QWidgetPrivate::_q_delayedDestroy(WId winId) +void QWidgetPrivate::_q_cleanupWinIds() { - delete winId; + foreach (WId wid, widCleanupList) + delete wid; + widCleanupList.clear(); } #endif diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index 2c89405..2f8545e 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -787,7 +787,7 @@ private: Q_DISABLE_COPY(QWidget) Q_PRIVATE_SLOT(d_func(), void _q_showIfNotHidden()) #ifdef Q_OS_SYMBIAN - Q_PRIVATE_SLOT(d_func(), void _q_delayedDestroy(WId winId)) + Q_PRIVATE_SLOT(d_func(), void void _q_cleanupWinIds()) #endif QWidgetData *data; diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index c00b8ed..e30497c 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -409,7 +409,7 @@ public: #ifdef Q_OS_SYMBIAN void setSoftKeys_sys(const QList<QAction*> &softkeys); void activateSymbianWindow(WId wid = 0); - void _q_delayedDestroy(WId winId); + void _q_cleanupWinIds(); #endif void raise_sys(); @@ -889,6 +889,7 @@ public: void s60UpdateIsOpaque(); void reparentChildren(); void registerTouchWindow(); + QList<WId> widCleanupList; #endif }; diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 5630706..3c2d63c 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -58,9 +58,7 @@ #endif // This is necessary in order to be able to perform delayed invocation on slots -// which take arguments of type WId. One example is -// QWidgetPrivate::_q_delayedDestroy, which is used to delay destruction of -// CCoeControl objects until after the CONE event handler has finished running. +// which take arguments of type WId. Q_DECLARE_METATYPE(WId) // Workaround for the fact that S60 SDKs 3.x do not contain the akntoolbar.h @@ -476,8 +474,8 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de // Delay deletion of the control in case this function is called in the // context of a CONE event handler such as // CCoeControl::ProcessPointerEventL - QMetaObject::invokeMethod(q, "_q_delayedDestroy", - Qt::QueuedConnection, Q_ARG(WId, destroyw)); + widCleanupList << destroyw; + QMetaObject::invokeMethod(q, "_q_cleanupWinIds", Qt::QueuedConnection); } if (q->testAttribute(Qt::WA_AcceptTouchEvents)) |