summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel/qwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/kernel/qwidget.cpp')
-rw-r--r--src/widgets/kernel/qwidget.cpp130
1 files changed, 91 insertions, 39 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index ec7b5ce69a..30daee1b79 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -83,6 +83,7 @@ using namespace Qt::StringLiterals;
Q_LOGGING_CATEGORY(lcWidgetPainting, "qt.widgets.painting", QtWarningMsg);
Q_LOGGING_CATEGORY(lcWidgetShowHide, "qt.widgets.showhide", QtWarningMsg);
+Q_LOGGING_CATEGORY(lcWidgetWindow, "qt.widgets.window", QtWarningMsg);
#ifndef QT_NO_DEBUG_STREAM
namespace {
@@ -10953,57 +10954,61 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
setWinId(0);
- if (parent != newparent) {
- QObjectPrivate::setParent_helper(newparent); //### why does this have to be done in the _sys function???
- if (q->windowHandle()) {
- q->windowHandle()->setFlags(f);
- QWidget *parentWithWindow =
- newparent ? (newparent->windowHandle() ? newparent : newparent->nativeParentWidget()) : nullptr;
- if (parentWithWindow) {
- QWidget *topLevel = parentWithWindow->window();
- if ((f & Qt::Window) && topLevel && topLevel->windowHandle()) {
- q->windowHandle()->setTransientParent(topLevel->windowHandle());
- q->windowHandle()->setParent(nullptr);
- } else {
- q->windowHandle()->setTransientParent(nullptr);
- q->windowHandle()->setParent(parentWithWindow->windowHandle());
- }
- } else {
- q->windowHandle()->setTransientParent(nullptr);
- q->windowHandle()->setParent(nullptr);
- }
- }
- }
-
if (!newparent) {
f |= Qt::Window;
if (parent)
targetScreen = q->parentWidget()->window()->screen();
}
+ const bool destroyWindow = (
+ // Reparenting top level to child
+ (oldFlags & Qt::Window) && !(f & Qt::Window)
+ // And we can dispose of the window
+ && wasCreated && !q->testAttribute(Qt::WA_NativeWindow)
+ );
+
+ if (parent != newparent) {
+ // Update object parent now, so we can resolve new parent window below
+ QObjectPrivate::setParent_helper(newparent);
+
+ if (q->windowHandle())
+ q->windowHandle()->setFlags(f);
+
+ // If the widget itself or any of its children have been created,
+ // we need to reparent their QWindows as well.
+ QWidget *parentWithWindow = closestParentWidgetWithWindowHandle();
+ // But if the widget is about to be destroyed we must skip the
+ // widget itself, and only reparent children.
+ if (destroyWindow)
+ reparentWidgetWindowChildren(parentWithWindow);
+ else
+ reparentWidgetWindows(parentWithWindow, f);
+ }
+
bool explicitlyHidden = isExplicitlyHidden();
- // Reparenting toplevel to child
- if (wasCreated && !(f & Qt::Window) && (oldFlags & Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow)) {
+ if (destroyWindow) {
if (extra && extra->hasWindowContainer)
QWindowContainer::toplevelAboutToBeDestroyed(q);
- QWindow *newParentWindow = newparent->windowHandle();
- if (!newParentWindow)
- if (QWidget *npw = newparent->nativeParentWidget())
- newParentWindow = npw->windowHandle();
-
- for (QObject *child : q->windowHandle()->children()) {
- QWindow *childWindow = qobject_cast<QWindow *>(child);
- if (!childWindow)
- continue;
-
- QWidgetWindow *childWW = qobject_cast<QWidgetWindow *>(childWindow);
- QWidget *childWidget = childWW ? childWW->widget() : nullptr;
- if (!childWW || (childWidget && childWidget->testAttribute(Qt::WA_NativeWindow)))
- childWindow->setParent(newParentWindow);
+ // There shouldn't be any QWindow children left, but if there
+ // are, re-parent them now, before we destroy.
+ if (!q->windowHandle()->children().isEmpty()) {
+ QWidget *parentWithWindow = closestParentWidgetWithWindowHandle();
+ QWindow *newParentWindow = parentWithWindow ? parentWithWindow->windowHandle() : nullptr;
+ for (QObject *child : q->windowHandle()->children()) {
+ if (QWindow *childWindow = qobject_cast<QWindow *>(child)) {
+ qCWarning(lcWidgetWindow) << "Reparenting" << childWindow
+ << "before destroying" << this;
+ childWindow->setParent(newParentWindow);
+ }
+ }
}
- q->destroy();
+
+ // We have reparented any child windows of the widget we are
+ // about to destroy to the new parent window handle, so we can
+ // safely destroy this widget without destroying sub windows.
+ q->destroy(true, false);
}
adjustFlags(f, q);
@@ -11029,6 +11034,53 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
}
}
+void QWidgetPrivate::reparentWidgetWindows(QWidget *parentWithWindow, Qt::WindowFlags windowFlags)
+{
+ if (QWindow *window = windowHandle()) {
+ // Reparent this QWindow, and all QWindow children will follow
+ if (parentWithWindow) {
+ // The reparented widget has not updated its window flags yet,
+ // so we can't ask the widget directly. And we can't use the
+ // QWindow flags, as unlike QWidgets the QWindow flags always
+ // reflect Qt::Window, even for child windows. And we can't use
+ // QWindow::isTopLevel() either, as that depends on the parent,
+ // which we are in the process of updating. So we propagate the
+ // new flags of the reparented window from setParent_sys().
+ if (windowFlags & Qt::Window) {
+ // Top level windows can only have transient parents,
+ // and the transient parent must be another top level.
+ QWidget *topLevel = parentWithWindow->window();
+ auto *transientParent = topLevel->windowHandle();
+ Q_ASSERT(transientParent);
+ qCDebug(lcWidgetWindow) << "Setting" << window << "transient parent to" << transientParent;
+ window->setTransientParent(transientParent);
+ window->setParent(nullptr);
+ } else {
+ auto *parentWindow = parentWithWindow->windowHandle();
+ qCDebug(lcWidgetWindow) << "Reparenting" << window << "into" << parentWindow;
+ window->setTransientParent(nullptr);
+ window->setParent(parentWindow);
+ }
+ } else {
+ qCDebug(lcWidgetWindow) << "Making" << window << "top level window";
+ window->setTransientParent(nullptr);
+ window->setParent(nullptr);
+ }
+ } else {
+ reparentWidgetWindowChildren(parentWithWindow);
+ }
+}
+
+void QWidgetPrivate::reparentWidgetWindowChildren(QWidget *parentWithWindow)
+{
+ for (auto *child : std::as_const(children)) {
+ if (auto *childWidget = qobject_cast<QWidget*>(child)) {
+ auto *childPrivate = QWidgetPrivate::get(childWidget);
+ childPrivate->reparentWidgetWindows(parentWithWindow);
+ }
+ }
+}
+
/*!
Scrolls the widget including its children \a dx pixels to the
right and \a dy downward. Both \a dx and \a dy may be negative.