macOS: Respect QWindow frame positioning on first show

When the QCocoaWindow is created it picks up the QWindow geometry,
and applies that to the NSWindow it creates. But since we haven't
created an NSWindow yet for the first step, our logic to adjust the
window geometry when the positionPolicy is WindowFrameInclusive is
a noop. As a result the NSWindow gets a client geometry corresponding
to what the user requested as the frame geometry.

To fix this we hook into [QNSWindow setContentView:], where we apply
QWindow properties to the NSWindow after creation.

The tst_QWindow::positioning test has been split out into a separate
framePositioning test.

Pick-to: 6.7 6.5
Change-Id: I85fe6ad10aee8346202de3d55d6b2cd89915c5df
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
(cherry picked from commit 31ec108dd08d6381a15e49b6fbec9337705c3b2a)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Tor Arne Vestbø 2024-07-03 16:47:49 +02:00 committed by Qt Cherry-pick Bot
parent 8fc29f208b
commit f31e7385c1
2 changed files with 64 additions and 27 deletions

View File

@ -225,6 +225,16 @@ NSWindow<QNSWindowProtocol> *qnswindow_cast(NSWindow *window)
m_platformWindow->setWindowFilePath(window->filePath()); // Also sets window icon m_platformWindow->setWindowFilePath(window->filePath()); // Also sets window icon
m_platformWindow->setWindowState(window->windowState()); m_platformWindow->setWindowState(window->windowState());
m_platformWindow->setOpacity(window->opacity()); m_platformWindow->setOpacity(window->opacity());
// At the time of creation the QNSWindow is given a geometry based
// on the client geometry of the QWindow. But at that point we don't
// know anything about the size of the NSWindow frame, which means
// that the logic in QCocoaWindow::setGeometry for adjusting the
// client geometry based on the QWindow's positionPolicy is a noop.
// Now that we have a NSWindow to read the frame from we re-apply
// the QWindow geometry, which will move the NSWindow if needed.
m_platformWindow->setGeometry(window->geometry());
m_platformWindow->setVisible(window->isVisible()); m_platformWindow->setVisible(window->isVisible());
} }

View File

@ -46,6 +46,8 @@ private slots:
void mapGlobal(); void mapGlobal();
void positioning_data(); void positioning_data();
void positioning(); void positioning();
void framePositioning();
void framePositioning_data();
void positioningDuringMinimized(); void positioningDuringMinimized();
void childWindowPositioning_data(); void childWindowPositioning_data();
void childWindowPositioning(); void childWindowPositioning();
@ -607,39 +609,64 @@ void tst_QWindow::positioning()
QTRY_COMPARE(originalPos, window.position()); QTRY_COMPARE(originalPos, window.position());
QTRY_COMPARE(originalFramePos, window.framePosition()); QTRY_COMPARE(originalFramePos, window.framePosition());
QTRY_COMPARE(originalMargins, window.frameMargins()); QTRY_COMPARE(originalMargins, window.frameMargins());
}
// if our positioning is actually fully respected by the window manager void tst_QWindow::framePositioning_data()
// test whether it correctly handles frame positioning as well {
if (originalPos == geometry.topLeft() && (originalMargins.top() != 0 || originalMargins.left() != 0)) { QTest::addColumn<bool>("showBeforePositioning");
const QScreen *screen = window.screen();
const QRect availableGeometry = screen->availableGeometry();
const QPoint framePos = availableGeometry.center();
window.reset(); QTest::newRow("before show") << false;
const QPoint oldFramePos = window.framePosition(); QTest::newRow("after show") << true;
window.setFramePosition(framePos); }
QTRY_VERIFY(window.received(QEvent::Move)); void tst_QWindow::framePositioning()
const int fuzz = int(QHighDpiScaling::factor(&window)); {
if (!qFuzzyCompareWindowPosition(window.framePosition(), framePos, fuzz)) { QFETCH(bool, showBeforePositioning);
qDebug() << "About to fail auto-test. Here is some additional information:";
qDebug() << "window.framePosition() == " << window.framePosition(); Window window;
qDebug() << "old frame position == " << oldFramePos; const QScreen *screen = window.screen();
qDebug() << "We received " << window.received(QEvent::Move) << " move events"; const QRect availableGeometry = screen->availableGeometry();
qDebug() << "frame positions after each move event:" << window.m_framePositionsOnMove; const QPoint screenCenter = availableGeometry.center();
}
QTRY_VERIFY2(qFuzzyCompareWindowPosition(window.framePosition(), framePos, fuzz), const QPoint oldFramePos = window.framePosition();
qPrintable(msgPointMismatch(window.framePosition(), framePos))); QMargins originalMargins;
if (showBeforePositioning) {
window.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&window));
originalMargins = window.frameMargins();
window.setFramePosition(screenCenter);
} else {
window.setFramePosition(screenCenter);
window.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&window));
}
QTRY_VERIFY(window.received(QEvent::Move));
const int fuzz = int(QHighDpiScaling::factor(&window));
if (!qFuzzyCompareWindowPosition(window.framePosition(), screenCenter, fuzz)) {
qDebug() << "About to fail auto-test. Here is some additional information:";
qDebug() << "window.framePosition() == " << window.framePosition();
qDebug() << "old frame position == " << oldFramePos;
qDebug() << "We received " << window.received(QEvent::Move) << " move events";
qDebug() << "frame positions after each move event:" << window.m_framePositionsOnMove;
}
QTRY_VERIFY2(qFuzzyCompareWindowPosition(window.framePosition(), screenCenter, fuzz),
qPrintable(msgPointMismatch(window.framePosition(), screenCenter)));
if (showBeforePositioning) {
// Repositioning should not affect existing margins
QTRY_COMPARE(originalMargins, window.frameMargins()); QTRY_COMPARE(originalMargins, window.frameMargins());
QCOMPARE(window.position(), window.framePosition() + QPoint(originalMargins.left(), originalMargins.top())); QCOMPARE(window.position(), window.framePosition() + QPoint(originalMargins.left(), originalMargins.top()));
// and back to regular positioning
window.reset();
window.setPosition(originalPos);
QTRY_VERIFY(window.received(QEvent::Move));
QTRY_COMPARE(originalPos, window.position());
} }
// Check that regular positioning still works
const QPoint screenCenterAdjusted = screenCenter + QPoint(50, 50);
window.reset();
window.setPosition(screenCenterAdjusted);
QTRY_VERIFY(window.received(QEvent::Move));
QTRY_COMPARE(screenCenterAdjusted, window.position());
} }
void tst_QWindow::positioningDuringMinimized() void tst_QWindow::positioningDuringMinimized()