From 65a991e57e862e498fcae741f03ba1727a76fc80 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 18 Sep 2014 17:37:23 +0200 Subject: [PATCH] Make sure we don't delete child QWindows if they have WA_NativeWindow set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deleting a QWindow automatically deletes its child windows because they are in the QObject hierarchy. However, if the user sets both WA_NativeWindow and WA_DontCreateNativeAncestors, we can't just delete that widget's QWindow. First because the widget doesn't get notified (and maybe it should be), and then because we may invalidate any reference to the QWindow the user may have kept. Our solution is to reparent the child QWindows into the new parent's closest QWindow. We must, however, take the precaution of not keeping any reference to the backing store in the platform window. Reparenting operations can trigger repaints on the platform window, but the backing store is not set and flushed until later. Task-number: QTBUG-38377 Change-Id: I353f5528f227a227b6d10419367cbe1d5d07a94e Reviewed-by: Jørgen Lind --- src/plugins/platforms/cocoa/qnsview.mm | 2 ++ src/widgets/kernel/qwidget_qpa.cpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 86691456b8..a4671845b7 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -580,6 +580,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; CGImageRelease(subMask); [self invalidateWindowShadowIfNeeded]; + + m_backingStore = 0; } - (BOOL) isFlipped diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index 5a4bd33672..b734307d40 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -284,6 +284,22 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f) if (wasCreated && !(f & Qt::Window) && (oldFlags & Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow)) { if (extra && extra->hasWindowContainer) QWindowContainer::toplevelAboutToBeDestroyed(q); + + QWindow *newParentWindow = newparent->windowHandle(); + if (!newParentWindow) + if (QWidget *npw = newparent->nativeParentWidget()) + newParentWindow = npw->windowHandle(); + + Q_FOREACH (QObject *child, q->windowHandle()->children()) { + QWindow *childWindow = qobject_cast(child); + if (!childWindow) + continue; + + QWidgetWindow *childWW = qobject_cast(childWindow); + QWidget *childWidget = childWW ? childWW->widget() : 0; + if (!childWW || (childWidget && childWidget->testAttribute(Qt::WA_NativeWindow))) + childWindow->setParent(newParentWindow); + } q->destroy(); }