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->setWindowState(window->windowState());
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());
}

View File

@ -46,6 +46,8 @@ private slots:
void mapGlobal();
void positioning_data();
void positioning();
void framePositioning();
void framePositioning_data();
void positioningDuringMinimized();
void childWindowPositioning_data();
void childWindowPositioning();
@ -607,39 +609,64 @@ void tst_QWindow::positioning()
QTRY_COMPARE(originalPos, window.position());
QTRY_COMPARE(originalFramePos, window.framePosition());
QTRY_COMPARE(originalMargins, window.frameMargins());
}
// if our positioning is actually fully respected by the window manager
// test whether it correctly handles frame positioning as well
if (originalPos == geometry.topLeft() && (originalMargins.top() != 0 || originalMargins.left() != 0)) {
const QScreen *screen = window.screen();
const QRect availableGeometry = screen->availableGeometry();
const QPoint framePos = availableGeometry.center();
void tst_QWindow::framePositioning_data()
{
QTest::addColumn<bool>("showBeforePositioning");
window.reset();
const QPoint oldFramePos = window.framePosition();
window.setFramePosition(framePos);
QTest::newRow("before show") << false;
QTest::newRow("after show") << true;
}
QTRY_VERIFY(window.received(QEvent::Move));
const int fuzz = int(QHighDpiScaling::factor(&window));
if (!qFuzzyCompareWindowPosition(window.framePosition(), framePos, 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(), framePos, fuzz),
qPrintable(msgPointMismatch(window.framePosition(), framePos)));
void tst_QWindow::framePositioning()
{
QFETCH(bool, showBeforePositioning);
Window window;
const QScreen *screen = window.screen();
const QRect availableGeometry = screen->availableGeometry();
const QPoint screenCenter = availableGeometry.center();
const QPoint oldFramePos = window.framePosition();
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());
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()