widgets: Translate QWindow move events into widget relative position

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ø <tor.arne.vestbo@qt.io>
bb10
Tor Arne Vestbø 2020-02-17 15:08:58 +01:00
parent fc3226e790
commit 8c3cc07bf5
3 changed files with 58 additions and 16 deletions

View File

@ -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)

View File

@ -125,7 +125,6 @@ private slots:
private:
void repaintWindow();
bool updateSize();
bool updatePos();
void updateMargins();
void updateNormalGeometry();

View File

@ -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<Qt::WidgetAttribute>;
void tst_QWidget::nativeWindowPosition_data()
{
QTest::addColumn<WidgetAttributes>("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: