diff options
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.h | 6 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 41 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnswindowdelegate.mm | 8 | ||||
-rw-r--r-- | tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 141 |
4 files changed, 135 insertions, 61 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 0c82d5b653..e3152f153c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -113,6 +113,7 @@ public: void setGeometry(const QRect &rect) override; QRect geometry() const override; + QRect normalGeometry() const override; void setCocoaGeometry(const QRect &rect); void setVisible(bool visible) override; @@ -171,6 +172,8 @@ public: Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState(); Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen(); + void windowWillZoom(); + bool windowShouldClose(); bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const; @@ -205,6 +208,8 @@ public: QPoint bottomLeftClippedByNSWindowOffset() const override; + void updateNormalGeometry(); + enum RecreationReason { RecreationNotNeeded = 0, ParentChanged = 0x1, @@ -262,6 +267,7 @@ public: // for QNSView bool m_frameStrutEventsEnabled; QRect m_exposedRect; + QRect m_normalGeometry; int m_registerTouchCount; bool m_resizableTransientParent; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 4450af0500..1bc53bde5c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -261,6 +261,40 @@ QRect QCocoaWindow::geometry() const return QPlatformWindow::geometry(); } +/*! + \brief the geometry of the window as it will appear when shown as + a normal (not maximized or full screen) top-level window. + + For child windows this property always holds an empty rectangle. + + \sa QWidget::normalGeometry() +*/ +QRect QCocoaWindow::normalGeometry() const +{ + if (!isContentView()) + return QRect(); + + // We only persist the normal the geometry when going into + // fullscreen and maximized states. For all other cases we + // can just report the geometry as is. + + if (!(windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized))) + return geometry(); + + return m_normalGeometry; +} + +void QCocoaWindow::updateNormalGeometry() +{ + if (!isContentView()) + return; + + if (windowState() != Qt::WindowNoState) + return; + + m_normalGeometry = geometry(); +} + void QCocoaWindow::setCocoaGeometry(const QRect &rect) { qCDebug(lcQpaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect; @@ -754,6 +788,11 @@ void QCocoaWindow::toggleMaximized() window.styleMask &= ~NSWindowStyleMaskResizable; } +void QCocoaWindow::windowWillZoom() +{ + updateNormalGeometry(); +} + void QCocoaWindow::toggleFullScreen() { const NSWindow *window = m_view.window; @@ -772,6 +811,8 @@ void QCocoaWindow::windowWillEnterFullScreen() if (!isContentView()) return; + updateNormalGeometry(); + // The NSWindow needs to be resizable, otherwise we'll end up with // the normal window geometry, centered in the middle of the screen // on a black background. The styleMask will be reset below. diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 8b80ba4076..ecaa14bcf7 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -112,6 +112,14 @@ static QCocoaWindow *toPlatformWindow(NSWindow *window) return QCocoaScreen::mapToNative(maximizedFrame); } +- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame +{ + QCocoaWindow *platformWindow = toPlatformWindow(window); + Q_ASSERT(platformWindow); + platformWindow->windowWillZoom(); + return YES; +} + - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu { Q_UNUSED(menu); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index a79c4aed8c..aca40103df 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -2486,6 +2486,24 @@ void tst_QWidget::activation() } #endif // Q_OS_WIN +struct WindowStateChangeWatcher : public QObject +{ + WindowStateChangeWatcher(QWidget *widget) + { + Q_ASSERT(widget->window()->windowHandle()); + widget->window()->windowHandle()->installEventFilter(this); + lastWindowStates = widget->window()->windowHandle()->windowState(); + } + Qt::WindowStates lastWindowStates; +protected: + bool eventFilter(QObject *receiver, QEvent *event) override + { + if (event->type() == QEvent::WindowStateChange) + lastWindowStates = static_cast<QWindow *>(receiver)->windowState(); + return QObject::eventFilter(receiver, event); + } +}; + void tst_QWidget::windowState() { #ifdef Q_OS_MACOS @@ -3165,10 +3183,6 @@ void tst_QWidget::hideWhenFocusWidgetIsChild() void tst_QWidget::normalGeometry() { -#ifdef Q_OS_MACOS - QSKIP("QTBUG-52974"); -#endif - if (m_platform == QStringLiteral("wayland")) QSKIP("Wayland: This fails. Figure out why."); QWidget parent; @@ -3179,96 +3193,101 @@ void tst_QWidget::normalGeometry() QCOMPARE(parent.normalGeometry(), parent.geometry()); QCOMPARE(child->normalGeometry(), QRect()); - const QRect testGeom = QRect(m_availableTopLeft + QPoint(100 ,100), m_testWidgetSize); - parent.setGeometry(testGeom); + parent.setGeometry(QRect(m_availableTopLeft + QPoint(100 ,100), m_testWidgetSize)); parent.showNormal(); QVERIFY(QTest::qWaitForWindowExposed(&parent)); - QApplication::processEvents(); + WindowStateChangeWatcher stateChangeWatcher(&parent); - QRect geom = parent.geometry(); - // ### the window manager places the top-left corner at - // ### 100,100... making geom something like 102,124 (offset by - // ### the frame/frame)... this indicates a rather large different - // ### between how X11 and Windows works - // QCOMPARE(geom, QRect(100, 100, 200, 200)); - QCOMPARE(parent.normalGeometry(), geom); + const QRect normalGeometry = parent.geometry(); + // We can't make any assumptions about the actual geometry compared to the + // requested geometry. In this test, we only care about normalGeometry. + QCOMPARE(parent.normalGeometry(), normalGeometry); parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized); - QTRY_VERIFY(parent.geometry() != geom); - QTRY_COMPARE(parent.normalGeometry(), geom); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_VERIFY(parent.geometry() != normalGeometry); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized)); - QTRY_COMPARE(parent.geometry(), geom); - QTRY_COMPARE(parent.normalGeometry(), geom); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_COMPARE(parent.geometry(), normalGeometry); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); parent.showMaximized(); - QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized); - QTRY_VERIFY(parent.geometry() != geom); - QCOMPARE(parent.normalGeometry(), geom); + QTRY_VERIFY(parent.windowHandle()->windowState() & Qt::WindowMaximized); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_VERIFY(parent.geometry() != normalGeometry); + QCOMPARE(parent.normalGeometry(), normalGeometry); parent.showNormal(); QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized)); - QTRY_COMPARE(parent.geometry(), geom); - QCOMPARE(parent.normalGeometry(), geom); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_COMPARE(parent.geometry(), normalGeometry); + QCOMPARE(parent.normalGeometry(), normalGeometry); + + parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen); + QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_VERIFY(parent.geometry() != normalGeometry); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); + + parent.setWindowState(Qt::WindowNoState); + QTRY_VERIFY(!(parent.windowState() & Qt::WindowFullScreen)); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_COMPARE(parent.geometry(), normalGeometry); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); + + parent.showFullScreen(); + QTRY_VERIFY(parent.window()->windowState() & Qt::WindowFullScreen); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_VERIFY(parent.geometry() != normalGeometry); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); + + parent.showNormal(); + QTRY_VERIFY(!(parent.windowHandle()->windowState() & Qt::WindowFullScreen)); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_COMPARE(parent.geometry(), normalGeometry); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); - parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized); - QTest::qWait(10); - parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); - QTest::qWait(10); if (m_platform == QStringLiteral("xcb")) QSKIP("QTBUG-26424"); - QTRY_VERIFY(parent.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized)); + + parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); + QTRY_VERIFY(stateChangeWatcher.lastWindowStates & Qt::WindowMaximized); + parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized); + QTRY_VERIFY(stateChangeWatcher.lastWindowStates & Qt::WindowMinimized); + + QTRY_COMPARE(parent.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized), Qt::WindowMinimized|Qt::WindowMaximized); + QTRY_VERIFY(stateChangeWatcher.lastWindowStates & (Qt::WindowMinimized|Qt::WindowMaximized)); // ### when minimized and maximized at the same time, the geometry // ### does *NOT* have to be the normal geometry, it could be the // ### maximized geometry. // QCOMPARE(parent.geometry(), geom); - QTRY_COMPARE(parent.normalGeometry(), geom); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized); - QTest::qWait(10); QTRY_VERIFY(!(parent.windowState() & Qt::WindowMinimized)); QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized); - QTRY_VERIFY(parent.geometry() != geom); - QTRY_COMPARE(parent.normalGeometry(), geom); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_VERIFY(parent.geometry() != normalGeometry); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized); - QTest::qWait(10); QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized)); - QTRY_COMPARE(parent.geometry(), geom); - QTRY_COMPARE(parent.normalGeometry(), geom); - - parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen); - QTest::qWait(10); - QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen); - QTRY_VERIFY(parent.geometry() != geom); - QTRY_COMPARE(parent.normalGeometry(), geom); - - parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen); - QTest::qWait(10); - QVERIFY(!(parent.windowState() & Qt::WindowFullScreen)); - QTRY_COMPARE(parent.geometry(), geom); - QTRY_COMPARE(parent.normalGeometry(), geom); - - parent.showFullScreen(); - QTest::qWait(10); - QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen); - QTRY_VERIFY(parent.geometry() != geom); - QTRY_COMPARE(parent.normalGeometry(), geom); - - parent.showNormal(); - QTest::qWait(10); - QTRY_VERIFY(!(parent.windowState() & Qt::WindowFullScreen)); - QTRY_COMPARE(parent.geometry(), geom); - QTRY_COMPARE(parent.normalGeometry(), geom); + QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState()); + QTRY_COMPARE(parent.geometry(), normalGeometry); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); parent.showNormal(); + stateChangeWatcher.lastWindowStates = {}; parent.setWindowState(Qt:: WindowFullScreen | Qt::WindowMaximized); parent.setWindowState(Qt::WindowMinimized | Qt:: WindowFullScreen | Qt::WindowMaximized); parent.setWindowState(Qt:: WindowFullScreen | Qt::WindowMaximized); - QTest::qWait(10); - QTRY_COMPARE(parent.normalGeometry(), geom); + // the actual window will be either fullscreen or maximized + QTRY_VERIFY(stateChangeWatcher.lastWindowStates & (Qt:: WindowFullScreen | Qt::WindowMaximized)); + QTRY_COMPARE(parent.normalGeometry(), normalGeometry); } void tst_QWidget::setGeometry() |