From 8c3cc07bf5254cb91b37a0000191871e9e32014e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 17 Feb 2020 15:08:58 +0100 Subject: widgets: Translate QWindow move events into widget relative position MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a widget backed by a QWindow is moved we need to translate the window geometry into a position relative to the parent widget. In most cases this was incidentally working due to widgets backed by QWindows always having QWindow parents too, so the QWindow position was applicable to the widget as well. But when Qt::WA_DontCreateNativeAncestors is used this is no longer the case, and we would end up with a widget geometry that included the parent positions all the way up to the next native widget. The updatePos() function has been squashed into handleMoveEvent(), since we need to ensure the position in the move event sent to the widget is correct as well. Change-Id: I55894ad7ab42a6d4d65e446a332ecdd7dcdcc263 Reviewed-by: Tor Arne Vestbø --- src/widgets/kernel/qwidgetwindow.cpp | 37 ++++++++++++++--------- src/widgets/kernel/qwidgetwindow_p.h | 1 - tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 36 ++++++++++++++++++++++ 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 904067afda..4ba5469e9d 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -727,19 +727,6 @@ bool QWidgetWindow::updateSize() return changed; } -bool QWidgetWindow::updatePos() -{ - bool changed = false; - if (m_widget->testAttribute(Qt::WA_OutsideWSRange)) - return changed; - if (m_widget->data->crect.topLeft() != geometry().topLeft()) { - changed = true; - m_widget->data->crect.moveTopLeft(geometry().topLeft()); - } - updateMargins(); - return changed; -} - void QWidgetWindow::updateMargins() { const QMargins margins = frameMargins(); @@ -800,8 +787,28 @@ void QWidgetWindow::updateNormalGeometry() void QWidgetWindow::handleMoveEvent(QMoveEvent *event) { - if (updatePos()) - QGuiApplication::forwardEvent(m_widget, event); + if (m_widget->testAttribute(Qt::WA_OutsideWSRange)) + return; + + auto oldPosition = m_widget->data->crect.topLeft(); + auto newPosition = geometry().topLeft(); + + if (!m_widget->isTopLevel()) { + if (auto *nativeParent = m_widget->nativeParentWidget()) + newPosition = m_widget->parentWidget()->mapFrom(nativeParent, newPosition); + } + + bool changed = newPosition != oldPosition; + + if (changed) + m_widget->data->crect.moveTopLeft(newPosition); + + updateMargins(); // FIXME: Only do when changed? + + if (changed) { + QMoveEvent widgetEvent(newPosition, oldPosition); + QGuiApplication::forwardEvent(m_widget, &widgetEvent, event); + } } void QWidgetWindow::handleResizeEvent(QResizeEvent *event) diff --git a/src/widgets/kernel/qwidgetwindow_p.h b/src/widgets/kernel/qwidgetwindow_p.h index 80a345465d..5689e129c3 100644 --- a/src/widgets/kernel/qwidgetwindow_p.h +++ b/src/widgets/kernel/qwidgetwindow_p.h @@ -125,7 +125,6 @@ private slots: private: void repaintWindow(); bool updateSize(); - bool updatePos(); void updateMargins(); void updateNormalGeometry(); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index d8f4881ffa..31e77b2a62 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -310,6 +310,8 @@ private slots: void hideOpaqueChildWhileHidden(); void updateWhileMinimized(); void alienWidgets(); + void nativeWindowPosition_data(); + void nativeWindowPosition(); void adjustSize(); void adjustSize_data(); void updateGeometry(); @@ -8211,6 +8213,40 @@ void tst_QWidget::alienWidgets() } } +using WidgetAttributes = QVector; + +void tst_QWidget::nativeWindowPosition_data() +{ + QTest::addColumn("attributes"); + + QTest::newRow("non-native all the way") + << WidgetAttributes{}; + QTest::newRow("native all the way") + << WidgetAttributes{ Qt::WA_NativeWindow }; + QTest::newRow("native with non-native ancestor") + << WidgetAttributes{ Qt::WA_NativeWindow, Qt::WA_DontCreateNativeAncestors }; +} + +void tst_QWidget::nativeWindowPosition() +{ + QWidget topLevel; + QWidget child(&topLevel); + child.move(5, 5); + + QWidget grandChild(&child); + grandChild.move(10, 10); + + QFETCH(WidgetAttributes, attributes); + for (auto attribute : attributes) + grandChild.setAttribute(attribute); + + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + + QCOMPARE(child.pos(), QPoint(5, 5)); + QCOMPARE(grandChild.pos(), QPoint(10, 10)); +} + class ASWidget : public QWidget { public: -- cgit v1.2.3