From a02959bb5b43a3f9d881e5213ceedf535202b6a1 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 1 Feb 2017 17:21:33 +0100 Subject: Make QWindow's windowState a QFlags of the WindowState This reflects QWidget API, and restores some behavior from Qt4. Some WM can have several state at the same time. On Plasma for example, when a window is both maximized and minimized, the "maximized" checkbox is checked from the taskbar entry. The API of QPlatformWindow was changed to take a QFlag and the platform plugins were adapted. - On XCB: Always send the full state to the WM. And read the full state. - On Windows: The code was originally written with '&' in Qt4, and was changed to == when porting. Some adaptation had to be made so the states would be preserved. - On macOS: Only a single state can be set and is reported back for now, with the possibly to expand this in the future. - Other platforms: Just do as before with the effective state. Task-number: QTBUG-57882 Task-number: QTBUG-52616 Task-number: QTBUG-52555 Change-Id: I7a1f7cac64236bbd4c591f796374315639233dad Reviewed-by: Gunnar Sletta Reviewed-by: Robin Burchell --- .../platforms/android/qandroidplatformwindow.cpp | 4 +- .../platforms/android/qandroidplatformwindow.h | 4 +- src/plugins/platforms/cocoa/qcocoawindow.h | 6 +- src/plugins/platforms/cocoa/qcocoawindow.mm | 8 +- src/plugins/platforms/haiku/qhaikuwindow.cpp | 21 +-- src/plugins/platforms/haiku/qhaikuwindow.h | 4 +- src/plugins/platforms/ios/qiosviewcontroller.mm | 4 +- src/plugins/platforms/ios/qioswindow.h | 2 +- src/plugins/platforms/ios/qioswindow.mm | 28 +--- .../platforms/mirclient/qmirclientwindow.cpp | 10 +- src/plugins/platforms/mirclient/qmirclientwindow.h | 2 +- .../platforms/offscreen/qoffscreenwindow.cpp | 23 +-- src/plugins/platforms/offscreen/qoffscreenwindow.h | 2 +- src/plugins/platforms/qnx/qqnxwindow.cpp | 27 +-- src/plugins/platforms/qnx/qqnxwindow.h | 4 +- src/plugins/platforms/windows/qwindowswindow.cpp | 184 +++++++++++++-------- src/plugins/platforms/windows/qwindowswindow.h | 9 +- src/plugins/platforms/winrt/qwinrtwindow.cpp | 21 ++- src/plugins/platforms/winrt/qwinrtwindow.h | 2 +- src/plugins/platforms/xcb/qxcbwindow.cpp | 117 +++++-------- src/plugins/platforms/xcb/qxcbwindow.h | 8 +- 21 files changed, 249 insertions(+), 241 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 97a1f30a35..74dc955814 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -56,7 +56,7 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) m_windowState = Qt::WindowNoState; static QAtomicInt winIdGenerator(1); m_windowId = winIdGenerator.fetchAndAddRelaxed(1); - setWindowState(window->windowState()); + setWindowState(window->windowStates()); } void QAndroidPlatformWindow::lower() @@ -103,7 +103,7 @@ void QAndroidPlatformWindow::setVisible(bool visible) QtAndroid::setApplicationActive(); } -void QAndroidPlatformWindow::setWindowState(Qt::WindowState state) +void QAndroidPlatformWindow::setWindowState(Qt::WindowStates state) { if (m_windowState == state) return; diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 91cb1e76e6..f2e51bd3df 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -59,7 +59,7 @@ public: void setVisible(bool visible) override; - void setWindowState(Qt::WindowState state) override; + void setWindowState(Qt::WindowStates state) override; void setWindowFlags(Qt::WindowFlags flags) override; Qt::WindowFlags windowFlags() const; void setParent(const QPlatformWindow *window) override; @@ -91,7 +91,7 @@ protected: protected: Qt::WindowFlags m_windowFlags; - Qt::WindowState m_windowState; + Qt::WindowStates m_windowState; WId m_windowId; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 567eb7438b..586e59bff4 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -168,7 +168,7 @@ public: void hide(bool becauseOfAncestor = false); void setVisible(bool visible) Q_DECL_OVERRIDE; void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; - void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; + void setWindowState(Qt::WindowStates state) Q_DECL_OVERRIDE; void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; void setWindowFilePath(const QString &filePath) Q_DECL_OVERRIDE; void setWindowIcon(const QIcon &icon) Q_DECL_OVERRIDE; @@ -292,7 +292,7 @@ protected: void removeChildWindow(QCocoaWindow *child); Qt::WindowState windowState() const; - void applyWindowState(Qt::WindowState newState); + void applyWindowState(Qt::WindowStates newState); void toggleMaximized(); void toggleFullScreen(); bool isTransitioningToFullScreen() const; @@ -313,7 +313,7 @@ public: // for QNSView bool m_viewIsToBeEmbedded; // true if the m_view is intended to be embedded in a "foreign" NSView hiearchy Qt::WindowFlags m_windowFlags; - Qt::WindowState m_lastReportedWindowState; + Qt::WindowStates m_lastReportedWindowState; Qt::WindowModality m_windowModality; QPointer m_enterLeaveTargetWindow; bool m_windowUnderMouse; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 75c13d6bbc..77f88cc061 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -762,7 +762,7 @@ void QCocoaWindow::setVisible(bool visible) // setWindowState might have been called while the window was hidden and // will not change the NSWindow state in that case. Sync up here: - applyWindowState(window()->windowState()); + applyWindowState(window()->windowStates()); if (window()->windowState() != Qt::WindowMinimized) { if ((window()->modality() == Qt::WindowModal @@ -1010,7 +1010,7 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) m_windowFlags = flags; } -void QCocoaWindow::setWindowState(Qt::WindowState state) +void QCocoaWindow::setWindowState(Qt::WindowStates state) { if (window()->isVisible()) applyWindowState(state); // Window state set for hidden windows take effect when show() is called @@ -1812,9 +1812,11 @@ QRect QCocoaWindow::nativeWindowGeometry() const updated yet, so window()->windowState() will reflect the previous state that was reported to QtGui. */ -void QCocoaWindow::applyWindowState(Qt::WindowState newState) +void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState) { const Qt::WindowState currentState = windowState(); + const Qt::WindowState newState = QWindowPrivate::effectiveState(requestedState); + if (newState == currentState) return; diff --git a/src/plugins/platforms/haiku/qhaikuwindow.cpp b/src/plugins/platforms/haiku/qhaikuwindow.cpp index 4634012eda..e19918d7bf 100644 --- a/src/plugins/platforms/haiku/qhaikuwindow.cpp +++ b/src/plugins/platforms/haiku/qhaikuwindow.cpp @@ -205,26 +205,23 @@ void QHaikuWindow::requestActivateWindow() m_window->Activate(true); } -void QHaikuWindow::setWindowState(Qt::WindowState state) +void QHaikuWindow::setWindowState(Qt::WindowStates state) { if (m_windowState == state) return; - const Qt::WindowState oldState = m_windowState; + const Qt::WindowStates oldState = m_windowState; m_windowState = state; - if (m_windowState == Qt::WindowMaximized) { - m_window->zoomByQt(); - } else if (m_windowState == Qt::WindowMinimized) { + if (m_windowState & Qt::WindowMinimized) m_window->Minimize(true); - } else if (m_windowState == Qt::WindowNoState) { - if (oldState == Qt::WindowMaximized) - m_window->zoomByQt(); // undo zoom - - if (oldState == Qt::WindowMinimized) - m_window->Minimize(false); // undo minimize - } + else if (m_windowState & Qt::WindowMaximized) + m_window->zoomByQt(); + else if (oldState & Qt::WindowMinimized) + m_window->Minimize(false); // undo minimize + else if (oldState & Qt::WindowMaximized) + m_window->zoomByQt(); // undo zoom } void QHaikuWindow::setWindowFlags(Qt::WindowFlags flags) diff --git a/src/plugins/platforms/haiku/qhaikuwindow.h b/src/plugins/platforms/haiku/qhaikuwindow.h index 75403fb421..5bfb99e532 100644 --- a/src/plugins/platforms/haiku/qhaikuwindow.h +++ b/src/plugins/platforms/haiku/qhaikuwindow.h @@ -94,7 +94,7 @@ public: BWindow* nativeHandle() const; void requestActivateWindow() Q_DECL_OVERRIDE; - void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; + void setWindowState(Qt::WindowStates state) Q_DECL_OVERRIDE; void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; @@ -120,7 +120,7 @@ private Q_SLOTS: void haikuDrawRequest(const QRect &rect); private: - Qt::WindowState m_windowState; + Qt::WindowStates m_windowState; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index c47b6d68b1..a4c151ed8b 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -176,8 +176,8 @@ return; // Re-apply window states to update geometry - if (window->windowState() & (Qt::WindowFullScreen | Qt::WindowMaximized)) - window->handle()->setWindowState(window->windowState()); + if (window->windowStates() & (Qt::WindowFullScreen | Qt::WindowMaximized)) + window->handle()->setWindowState(window->windowStates()); } // Even if the root view controller has both wantsFullScreenLayout and diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 81fad420f6..da8a6aabdc 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -62,7 +62,7 @@ public: void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; - void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; + void setWindowState(Qt::WindowStates state) Q_DECL_OVERRIDE; void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE; void handleContentOrientationChange(Qt::ScreenOrientation orientation) Q_DECL_OVERRIDE; void setVisible(bool visible) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 8ff0dfbd5f..4e6d48423d 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -73,7 +73,7 @@ QIOSWindow::QIOSWindow(QWindow *window) m_normalGeometry = initialGeometry(window, QPlatformWindow::geometry(), screen()->availableGeometry().width(), screen()->availableGeometry().height()); - setWindowState(window->windowState()); + setWindowState(window->windowStates()); setOpacity(window->opacity()); Qt::ScreenOrientation initialOrientation = window->contentOrientation(); @@ -229,7 +229,7 @@ bool QIOSWindow::isExposed() const && window()->isVisible() && !window()->geometry().isEmpty(); } -void QIOSWindow::setWindowState(Qt::WindowState state) +void QIOSWindow::setWindowState(Qt::WindowStates state) { // Update the QWindow representation straight away, so that // we can update the statusbar visibility based on the new @@ -239,25 +239,15 @@ void QIOSWindow::setWindowState(Qt::WindowState state) if (window()->isTopLevel() && window()->isVisible() && window()->isActive()) [m_view.qtViewController updateProperties]; - switch (state) { - case Qt::WindowNoState: - applyGeometry(m_normalGeometry); - break; - case Qt::WindowMaximized: + if (state & Qt::WindowMinimized) + applyGeometry(QRect()); + else if (state & Qt::WindowFullScreen) + applyGeometry(screen()->geometry()); + else if (state & Qt::WindowMaximized) applyGeometry(window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint ? screen()->geometry() : screen()->availableGeometry()); - break; - case Qt::WindowFullScreen: - applyGeometry(screen()->geometry()); - break; - case Qt::WindowMinimized: - applyGeometry(QRect()); - break; - case Qt::WindowActive: - Q_UNREACHABLE(); - default: - Q_UNREACHABLE(); - } + else + applyGeometry(m_normalGeometry); } void QIOSWindow::setParent(const QPlatformWindow *parentWindow) diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.cpp b/src/plugins/platforms/mirclient/qmirclientwindow.cpp index adc8ae652a..369073a70e 100644 --- a/src/plugins/platforms/mirclient/qmirclientwindow.cpp +++ b/src/plugins/platforms/mirclient/qmirclientwindow.cpp @@ -785,8 +785,16 @@ void QMirClientWindow::handleSurfaceStateChanged(Qt::WindowState state) QWindowSystemInterface::handleWindowStateChanged(window(), state); } -void QMirClientWindow::setWindowState(Qt::WindowState state) +void QMirClientWindow::setWindowState(Qt::WindowStates states) { + Qt::WindowState state = Qt::WindowNoState; + if (states & Qt::WindowMinimized) + state = Qt::WindowMinimized; + else if (states & Qt::WindowFullScreen) + state = Qt::WindowFullScreen; + else if (states & Qt::WindowMaximized) + state = Qt::WindowMaximized; + QMutexLocker lock(&mMutex); qCDebug(mirclient, "setWindowState(window=%p, %s)", this, qtWindowStateToStr(state)); diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.h b/src/plugins/platforms/mirclient/qmirclientwindow.h index 324e7691ff..6c5695d62f 100644 --- a/src/plugins/platforms/mirclient/qmirclientwindow.h +++ b/src/plugins/platforms/mirclient/qmirclientwindow.h @@ -73,7 +73,7 @@ public: WId winId() const override; QRect geometry() const override; void setGeometry(const QRect&) override; - void setWindowState(Qt::WindowState state) override; + void setWindowState(Qt::WindowStates state) override; void setWindowFlags(Qt::WindowFlags flags) override; void setVisible(bool visible) override; void setWindowTitle(const QString &title) override; diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp index 892168a1dc..c37d869597 100644 --- a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp @@ -56,7 +56,7 @@ QOffscreenWindow::QOffscreenWindow(QWindow *window) if (window->windowState() == Qt::WindowNoState) setGeometry(window->geometry()); else - setWindowState(window->windowState()); + setWindowState(window->windowStates()); QWindowSystemInterface::flushWindowSystemEvents(); @@ -163,26 +163,19 @@ void QOffscreenWindow::setFrameMarginsEnabled(bool enabled) m_margins = QMargins(0, 0, 0, 0); } -void QOffscreenWindow::setWindowState(Qt::WindowState state) +void QOffscreenWindow::setWindowState(Qt::WindowStates state) { - setFrameMarginsEnabled(state != Qt::WindowFullScreen); + setFrameMarginsEnabled(!(state & Qt::WindowFullScreen)); m_positionIncludesFrame = false; - switch (state) { - case Qt::WindowFullScreen: + if (state & Qt::WindowMinimized) + ; // nothing to do + else if (state & Qt::WindowFullScreen) setGeometryImpl(screen()->geometry()); - break; - case Qt::WindowMaximized: + else if (state & Qt::WindowMaximized) setGeometryImpl(screen()->availableGeometry().adjusted(m_margins.left(), m_margins.top(), -m_margins.right(), -m_margins.bottom())); - break; - case Qt::WindowMinimized: - break; - case Qt::WindowNoState: + else setGeometryImpl(m_normalGeometry); - break; - default: - break; - } QWindowSystemInterface::handleWindowStateChanged(window(), state); } diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.h b/src/plugins/platforms/offscreen/qoffscreenwindow.h index f75458eb8e..0dced9680a 100644 --- a/src/plugins/platforms/offscreen/qoffscreenwindow.h +++ b/src/plugins/platforms/offscreen/qoffscreenwindow.h @@ -54,7 +54,7 @@ public: ~QOffscreenWindow(); void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; - void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; + void setWindowState(Qt::WindowStates states) Q_DECL_OVERRIDE; QMargins frameMargins() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 6fd0191e43..e066ab37c2 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -586,7 +586,7 @@ void QQnxWindow::setFocus(screen_window_t newFocusWindow) } } -void QQnxWindow::setWindowState(Qt::WindowState state) +void QQnxWindow::setWindowState(Qt::WindowStates state) { qWindowDebug() << "state =" << state; @@ -749,32 +749,19 @@ void QQnxWindow::updateZorder(screen_window_t window, int &topZorder) void QQnxWindow::applyWindowState() { - switch (m_windowState) { - - // WindowActive is not an accepted parameter according to the docs - case Qt::WindowActive: - return; - - case Qt::WindowMinimized: + if (m_windowState & Qt::WindowMinimized) { minimize(); if (m_unmaximizedGeometry.isValid()) setGeometry(m_unmaximizedGeometry); else setGeometry(m_screen->geometry()); - - break; - - case Qt::WindowMaximized: - case Qt::WindowFullScreen: + } else if (m_windowState & (Qt::WindowMaximized | Qt::WindowFullScreen)) { m_unmaximizedGeometry = geometry(); - setGeometry(m_windowState == Qt::WindowMaximized ? m_screen->availableGeometry() : m_screen->geometry()); - break; - - case Qt::WindowNoState: - if (m_unmaximizedGeometry.isValid()) - setGeometry(m_unmaximizedGeometry); - break; + setGeometry(m_windowState & Qt::WindowFullScreen ? m_screen->geometry() + : m_screen->availableGeometry()); + } else if (m_unmaximizedGeometry.isValid()) { + setGeometry(m_unmaximizedGeometry); } } diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index e248e04462..f96edc49e4 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -85,7 +85,7 @@ public: void raise() override; void lower() override; void requestActivateWindow() override; - void setWindowState(Qt::WindowState state) override; + void setWindowState(Qt::WindowStates state) override; void setExposed(bool exposed); void propagateSizeHints() override; @@ -141,7 +141,7 @@ private: bool m_visible; bool m_exposed; QRect m_unmaximizedGeometry; - Qt::WindowState m_windowState; + Qt::WindowStates m_windowState; QString m_mmRendererWindowName; screen_window_t m_mmRendererWindow; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index ea0ee52669..8950ec3bfc 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1071,7 +1071,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) updateDropSite(window()->isTopLevel()); registerTouchWindow(); - setWindowState(aWindow->windowState()); + setWindowState(aWindow->windowStates()); const qreal opacity = qt_window_private(aWindow)->opacity; if (!qFuzzyCompare(opacity, qreal(1.0))) setOpacity(opacity); @@ -1338,20 +1338,48 @@ static inline bool testShowWithoutActivating(const QWindow *window) return showWithoutActivating.isValid() && showWithoutActivating.toBool(); } +static void setMinimizedGeometry(HWND hwnd, const QRect &r) +{ + WINDOWPLACEMENT windowPlacement; + windowPlacement.length = sizeof(WINDOWPLACEMENT); + if (GetWindowPlacement(hwnd, &windowPlacement)) { + windowPlacement.showCmd = SW_SHOWMINIMIZED; + windowPlacement.rcNormalPosition = RECTfromQRect(r); + SetWindowPlacement(hwnd, &windowPlacement); + } +} + +static void setRestoreMaximizedFlag(HWND hwnd, bool set = true) +{ + // Let Windows know that we need to restore as maximized + WINDOWPLACEMENT windowPlacement; + windowPlacement.length = sizeof(WINDOWPLACEMENT); + if (GetWindowPlacement(hwnd, &windowPlacement)) { + if (set) + windowPlacement.flags |= WPF_RESTORETOMAXIMIZED; + else + windowPlacement.flags &= ~WPF_RESTORETOMAXIMIZED; + SetWindowPlacement(hwnd, &windowPlacement); + } +} + // partially from QWidgetPrivate::show_sys() void QWindowsWindow::show_sys() const { int sm = SW_SHOWNORMAL; bool fakedMaximize = false; + bool restoreMaximize = false; const QWindow *w = window(); const Qt::WindowFlags flags = w->flags(); const Qt::WindowType type = w->type(); if (w->isTopLevel()) { - const Qt::WindowState state = w->windowState(); + const Qt::WindowStates state = w->windowStates(); if (state & Qt::WindowMinimized) { sm = SW_SHOWMINIMIZED; if (!isVisible()) sm = SW_SHOWMINNOACTIVE; + if (state & Qt::WindowMaximized) + restoreMaximize = true; } else { updateTransientParent(); if (state & Qt::WindowMaximized) { @@ -1372,7 +1400,7 @@ void QWindowsWindow::show_sys() const if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool || testShowWithoutActivating(w)) sm = SW_SHOWNOACTIVATE; - if (w->windowState() & Qt::WindowMaximized) + if (w->windowStates() & Qt::WindowMaximized) setFlag(WithinMaximize); // QTBUG-8361 ShowWindow(m_data.hwnd, sm); @@ -1385,6 +1413,8 @@ void QWindowsWindow::show_sys() const SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } + if (restoreMaximize) + setRestoreMaximizedFlag(m_data.hwnd); } void QWindowsWindow::setParent(const QPlatformWindow *newParent) @@ -1458,7 +1488,8 @@ static QRect normalFrameGeometry(HWND hwnd) QRect QWindowsWindow::normalGeometry() const { // Check for fake 'fullscreen' mode. - const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen; + const bool fakeFullScreen = + m_savedFrameGeometry.isValid() && (window()->windowStates() & Qt::WindowFullScreen); const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; @@ -1473,13 +1504,15 @@ void QWindowsWindow::setGeometry(const QRect &rectIn) const QMargins margins = frameMargins(); rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top())); } - if (m_windowState == Qt::WindowMinimized) + if (m_windowState & Qt::WindowMinimized) m_data.geometry = rect; // Otherwise set by handleGeometryChange() triggered by event. if (m_data.hwnd) { // A ResizeEvent with resulting geometry will be sent. If we cannot // achieve that size (for example, window title minimal constraint), // notify and warn. + setFlag(WithinSetGeometry); setGeometry_sys(rect); + clearFlag(WithinSetGeometry); if (m_data.geometry != rect) { qWarning("%s: Unable to set geometry %dx%d+%d+%d on %s/'%s'." " Resulting geometry: %dx%d+%d+%d " @@ -1516,18 +1549,21 @@ void QWindowsWindow::handleResized(int wParam) case SIZE_MAXSHOW: return; case SIZE_MINIMIZED: // QTBUG-53577, prevent state change events during programmatic state change - if (!testFlag(WithinSetStyle)) - handleWindowStateChange(Qt::WindowMinimized); + if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry)) + handleWindowStateChange(m_windowState | Qt::WindowMinimized); return; case SIZE_MAXIMIZED: - if (!testFlag(WithinSetStyle)) - handleWindowStateChange(Qt::WindowMaximized); + if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry)) + handleWindowStateChange(Qt::WindowMaximized | (isFullScreen_sys() ? Qt::WindowFullScreen + : Qt::WindowNoState)); handleGeometryChange(); break; case SIZE_RESTORED: - if (!testFlag(WithinSetStyle)) { + if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry)) { if (isFullScreen_sys()) - handleWindowStateChange(Qt::WindowFullScreen); + handleWindowStateChange( + Qt::WindowFullScreen + | (testFlag(MaximizeToFullScreen) ? Qt::WindowMaximized : Qt::WindowNoState)); else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) handleWindowStateChange(Qt::WindowNoState); } @@ -1714,20 +1750,16 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, return result; } -void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) +void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << "\n from " << m_windowState << " to " << state; m_windowState = state; QWindowSystemInterface::handleWindowStateChanged(window(), state); - switch (state) { - case Qt::WindowMinimized: + if (state & Qt::WindowMinimized) { handleHidden(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now. - break; - case Qt::WindowMaximized: - case Qt::WindowFullScreen: - case Qt::WindowNoState: { + } else { // QTBUG-17548: We send expose events when receiving WM_Paint, but for // layered windows and transient children, we won't receive any WM_Paint. QWindow *w = window(); @@ -1748,13 +1780,9 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) if (exposeEventsSent && !QWindowsContext::instance()->asyncExpose()) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); } - break; - default: - break; - } } -void QWindowsWindow::setWindowState(Qt::WindowState state) +void QWindowsWindow::setWindowState(Qt::WindowStates state) { if (m_data.hwnd) { setWindowState_sys(state); @@ -1783,18 +1811,19 @@ bool QWindowsWindow::isFullScreen_sys() const to ShowWindow. */ -void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) +void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState) { - const Qt::WindowState oldState = m_windowState; + const Qt::WindowStates oldState = m_windowState; if (oldState == newState) return; qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << " from " << oldState << " to " << newState; const bool visible = isVisible(); + auto stateChange = oldState ^ newState; - if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) { - if (newState == Qt::WindowFullScreen) { + if (stateChange & Qt::WindowFullScreen) { + if (newState & Qt::WindowFullScreen) { #ifndef Q_FLATTEN_EXPOSE UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; #else @@ -1805,7 +1834,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) // Window state but emulated by changing geometry and style. if (!m_savedStyle) { m_savedStyle = style(); - if (oldState == Qt::WindowMinimized || oldState == Qt::WindowMaximized) { + if ((oldState & Qt::WindowMinimized) || (oldState & Qt::WindowMaximized)) { const QRect nf = normalFrameGeometry(m_data.hwnd); if (nf.isValid()) m_savedFrameGeometry = nf; @@ -1813,6 +1842,8 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) m_savedFrameGeometry = frameGeometry_sys(); } } + if (newState & Qt::WindowMaximized) + setFlag(MaximizeToFullScreen); if (m_savedStyle & WS_SYSMENU) newStyle |= WS_SYSMENU; if (visible) @@ -1826,15 +1857,23 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) if (!screen) screen = QGuiApplication::primaryScreen(); const QRect r = screen ? QHighDpi::toNativePixels(screen->geometry(), window()) : m_savedFrameGeometry; - const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; - const bool wasSync = testFlag(SynchronousGeometryChangeEvent); - setFlag(SynchronousGeometryChangeEvent); - SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); - if (!wasSync) - clearFlag(SynchronousGeometryChangeEvent); - QWindowSystemInterface::handleGeometryChange(window(), r); - QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); - } else if (newState != Qt::WindowMinimized) { + + if (newState & Qt::WindowMinimized) { + setMinimizedGeometry(m_data.hwnd, r); + if (stateChange & Qt::WindowMaximized) + setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); + } else { + const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; + const bool wasSync = testFlag(SynchronousGeometryChangeEvent); + setFlag(SynchronousGeometryChangeEvent); + SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); + if (!wasSync) + clearFlag(SynchronousGeometryChangeEvent); + clearFlag(MaximizeToFullScreen); + QWindowSystemInterface::handleGeometryChange(window(), r); + QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); + } + } else { // Restore saved state. unsigned newStyle = m_savedStyle ? m_savedStyle : style(); if (visible) @@ -1848,43 +1887,58 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) if (!screen->geometry().intersects(m_savedFrameGeometry)) m_savedFrameGeometry.moveTo(screen->geometry().topLeft()); - UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE; - if (!m_savedFrameGeometry.isValid()) - swpf |= SWP_NOSIZE | SWP_NOMOVE; - const bool wasSync = testFlag(SynchronousGeometryChangeEvent); - setFlag(SynchronousGeometryChangeEvent); - // After maximized/fullscreen; the window can be in a maximized state. Clear - // it before applying the normal geometry. - if (windowVisibility_sys(m_data.hwnd) == QWindow::Maximized) - ShowWindow(m_data.hwnd, SW_SHOWNOACTIVATE); - SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(), - m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf); - if (!wasSync) - clearFlag(SynchronousGeometryChangeEvent); - // preserve maximized state - if (visible) { - setFlag(WithinMaximize); - ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNA); - clearFlag(WithinMaximize); + if (newState & Qt::WindowMinimized) { + setMinimizedGeometry(m_data.hwnd, m_savedFrameGeometry); + if (stateChange & Qt::WindowMaximized) + setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); + } else { + UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE; + if (!m_savedFrameGeometry.isValid()) + swpf |= SWP_NOSIZE | SWP_NOMOVE; + const bool wasSync = testFlag(SynchronousGeometryChangeEvent); + setFlag(SynchronousGeometryChangeEvent); + // After maximized/fullscreen; the window can be in a maximized state. Clear + // it before applying the normal geometry. + if (windowVisibility_sys(m_data.hwnd) == QWindow::Maximized) + ShowWindow(m_data.hwnd, SW_SHOWNOACTIVATE); + SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(), + m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf); + if (!wasSync) + clearFlag(SynchronousGeometryChangeEvent); + // preserve maximized state + if (visible) { + setFlag(WithinMaximize); + ShowWindow(m_data.hwnd, + (newState & Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNA); + clearFlag(WithinMaximize); + } } m_savedStyle = 0; m_savedFrameGeometry = QRect(); } - } else if ((oldState == Qt::WindowMaximized) != (newState == Qt::WindowMaximized)) { - if (visible && !(newState == Qt::WindowMinimized)) { + } else if ((oldState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) { + if (visible && !(newState & Qt::WindowMinimized)) { setFlag(WithinMaximize); - if (newState == Qt::WindowFullScreen) + if (newState & Qt::WindowFullScreen) setFlag(MaximizeToFullScreen); - ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE); + ShowWindow(m_data.hwnd, + (newState & Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE); clearFlag(WithinMaximize); clearFlag(MaximizeToFullScreen); + } else if (visible && (oldState & newState & Qt::WindowMinimized)) { + // change of the maximized state while keeping minimized + setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); } } - if ((oldState == Qt::WindowMinimized) != (newState == Qt::WindowMinimized)) { - if (visible) - ShowWindow(m_data.hwnd, (newState == Qt::WindowMinimized) ? SW_MINIMIZE : - (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNORMAL); + if (stateChange & Qt::WindowMinimized) { + if (visible) { + ShowWindow(m_data.hwnd, + (newState & Qt::WindowMinimized) ? SW_MINIMIZE : + (newState & Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNORMAL); + if ((newState & Qt::WindowMinimized) && (oldState ^ newState & Qt::WindowMaximized)) + setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); + } } qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() << newState; } @@ -2145,7 +2199,7 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const hint.applyToMinMaxInfo(m_data.hwnd, mmi); } - if ((testFlag(WithinMaximize) || (window()->windowState() == Qt::WindowMinimized)) + if ((testFlag(WithinMaximize) || (window()->windowStates() & Qt::WindowMinimized)) && (m_data.flags & Qt::FramelessWindowHint)) { // This block fixes QTBUG-8361: Frameless windows shouldn't cover the // taskbar when maximized @@ -2175,7 +2229,7 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re // QTBUG-32663, suppress resize cursor for fixed size windows. const QWindow *w = window(); if (!w->isTopLevel() // Task 105852, minimized windows need to respond to user input. - || (m_windowState != Qt::WindowNoState && m_windowState != Qt::WindowActive) + || !(m_windowState & ~Qt::WindowActive) || (m_data.flags & Qt::FramelessWindowHint)) { return false; } diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 5664539058..b55529588c 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -188,6 +188,7 @@ public: { AutoMouseCapture = 0x1, //! Automatic mouse capture on button press. WithinSetParent = 0x2, + WithinSetGeometry = 0x8, OpenGLSurface = 0x10, OpenGL_ES2 = 0x20, OpenGLDoubleBuffered = 0x40, @@ -230,7 +231,7 @@ public: QPoint mapFromGlobal(const QPoint &pos) const override; void setWindowFlags(Qt::WindowFlags flags) override; - void setWindowState(Qt::WindowState state) override; + void setWindowState(Qt::WindowStates state) override; void setParent(const QPlatformWindow *window) override; @@ -323,7 +324,7 @@ private: inline void show_sys() const; inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; inline bool isFullScreen_sys() const; - inline void setWindowState_sys(Qt::WindowState newState); + inline void setWindowState_sys(Qt::WindowStates newState); inline void setParent_sys(const QPlatformWindow *parent); inline void updateTransientParent() const; void destroyWindow(); @@ -331,14 +332,14 @@ private: void setDropSiteEnabled(bool enabled); void updateDropSite(bool topLevel); void handleGeometryChange(); - void handleWindowStateChange(Qt::WindowState state); + void handleWindowStateChange(Qt::WindowStates state); inline void destroyIcon(); void fireExpose(const QRegion ®ion, bool force=false); mutable QWindowsWindowData m_data; mutable unsigned m_flags = WithinCreate; HDC m_hdc = 0; - Qt::WindowState m_windowState = Qt::WindowNoState; + Qt::WindowStates m_windowState = Qt::WindowNoState; qreal m_opacity = 1; #ifndef QT_NO_CURSOR CursorHandlePtr m_cursor; diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index c40a1b8c45..cbf0ba36c9 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -91,7 +91,7 @@ public: QSurfaceFormat surfaceFormat; QString windowTitle; - Qt::WindowState state; + Qt::WindowStates state; EGLDisplay display; EGLSurface surface; @@ -158,7 +158,7 @@ QWinRTWindow::QWinRTWindow(QWindow *window) Q_ASSERT_SUCCEEDED(hr); setWindowFlags(window->flags()); - setWindowState(window->windowState()); + setWindowState(window->windowStates()); setWindowTitle(window->title()); setGeometry(window->geometry()); @@ -323,7 +323,7 @@ qreal QWinRTWindow::devicePixelRatio() const return screen()->devicePixelRatio(); } -void QWinRTWindow::setWindowState(Qt::WindowState state) +void QWinRTWindow::setWindowState(Qt::WindowStates state) { Q_D(QWinRTWindow); qCDebug(lcQpaWindows) << __FUNCTION__ << this << state; @@ -331,7 +331,13 @@ void QWinRTWindow::setWindowState(Qt::WindowState state) if (d->state == state) return; - if (state == Qt::WindowFullScreen) { + if (state & Qt::WindowMinimized) { + setUIElementVisibility(d->uiElement.Get(), false); + d->state = state; + return; + } + + if (state & Qt::WindowFullScreen) { HRESULT hr; boolean success; hr = QEventDispatcherWinRT::runOnXamlThread([&hr, &success]() { @@ -356,7 +362,7 @@ void QWinRTWindow::setWindowState(Qt::WindowState state) return; } - if (d->state == Qt::WindowFullScreen) { + if (d->state & Qt::WindowFullScreen) { HRESULT hr; hr = QEventDispatcherWinRT::runOnXamlThread([&hr]() { ComPtr applicationViewStatics; @@ -378,10 +384,7 @@ void QWinRTWindow::setWindowState(Qt::WindowState state) } } - if (state == Qt::WindowMinimized) - setUIElementVisibility(d->uiElement.Get(), false); - - if (d->state == Qt::WindowMinimized || state == Qt::WindowNoState || state == Qt::WindowActive) + if (d->state & Qt::WindowMinimized || state == Qt::WindowNoState || state == Qt::WindowActive) setUIElementVisibility(d->uiElement.Get(), true); d->state = state; diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 26c2fa800d..a8992450b9 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -68,7 +68,7 @@ public: WId winId() const override; qreal devicePixelRatio() const override; - void setWindowState(Qt::WindowState state) override; + void setWindowState(Qt::WindowStates state) override; bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 52e74c2364..e2c25df111 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -552,7 +552,7 @@ void QXcbWindow::create() connection()->xi2Select(m_window); #endif - setWindowState(window()->windowState()); + setWindowState(window()->windowStates()); setWindowFlags(window()->flags()); setWindowTitle(window()->title()); @@ -762,7 +762,7 @@ void QXcbWindow::show() xcb_wm_hints_t hints; xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, NULL); - if (window()->windowState() & Qt::WindowMinimized) + if (window()->windowStates() & Qt::WindowMinimized) xcb_wm_hints_set_iconic(&hints); else xcb_wm_hints_set_normal(&hints); @@ -1215,66 +1215,43 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) (const char *)&event); } -void QXcbWindow::setWindowState(Qt::WindowState state) +void QXcbWindow::setWindowState(Qt::WindowStates state) { if (state == m_windowState) return; - // unset old state - switch (m_windowState) { - case Qt::WindowMinimized: + if ((m_windowState & Qt::WindowMinimized) && !(state & Qt::WindowMinimized)) { xcb_map_window(xcb_connection(), m_window); - break; - case Qt::WindowMaximized: - changeNetWmState(false, - atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), - atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); - break; - case Qt::WindowFullScreen: - changeNetWmState(false, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - break; - default: - break; + } else if (!(m_windowState & Qt::WindowMinimized) && (state & Qt::WindowMinimized)) { + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.sequence = 0; + event.window = m_window; + event.type = atom(QXcbAtom::WM_CHANGE_STATE); + event.data.data32[0] = XCB_WM_STATE_ICONIC; + event.data.data32[1] = 0; + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), + XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char *)&event); + m_minimized = true; } - // set new state - switch (state) { - case Qt::WindowMinimized: - { - xcb_client_message_event_t event; - - event.response_type = XCB_CLIENT_MESSAGE; - event.format = 32; - event.sequence = 0; - event.window = m_window; - event.type = atom(QXcbAtom::WM_CHANGE_STATE); - event.data.data32[0] = XCB_WM_STATE_ICONIC; - event.data.data32[1] = 0; - event.data.data32[2] = 0; - event.data.data32[3] = 0; - event.data.data32[4] = 0; - - xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), - XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - (const char *)&event); - } - break; - case Qt::WindowMaximized: - changeNetWmState(true, - atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + if ((m_windowState ^ state) & Qt::WindowMaximized) { + changeNetWmState(state & Qt::WindowMaximized, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); - break; - case Qt::WindowFullScreen: - changeNetWmState(true, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); - break; - case Qt::WindowNoState: - break; - default: - break; } - connection()->sync(); + if ((m_windowState ^ state) & Qt::WindowFullScreen) { + changeNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + } + connection()->sync(); m_windowState = state; } @@ -1346,10 +1323,10 @@ void QXcbWindow::updateNetWmStateBeforeMap() states |= NetWmStateBelow; } - if (window()->windowState() & Qt::WindowFullScreen) + if (window()->windowStates() & Qt::WindowFullScreen) states |= NetWmStateFullScreen; - if (window()->windowState() & Qt::WindowMaximized) { + if (window()->windowStates() & Qt::WindowMaximized) { states |= NetWmStateMaximizedHorz; states |= NetWmStateMaximizedVert; } @@ -2486,39 +2463,33 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev if (propertyDeleted) return; - Qt::WindowState newState = Qt::WindowNoState; + Qt::WindowStates newState = Qt::WindowNoState; + if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'. auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), 0, m_window, atom(QXcbAtom::WM_STATE), XCB_ATOM_ANY, 0, 1024); if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) { const quint32 *data = (const quint32 *)xcb_get_property_value(reply.get()); - if (reply->length != 0) { - if (data[0] == XCB_WM_STATE_ICONIC - || (data[0] == XCB_WM_STATE_WITHDRAWN - && m_lastWindowStateEvent == Qt::WindowMinimized)) { - newState = Qt::WindowMinimized; - } - } + if (reply->length != 0) + m_minimized = (data[0] == XCB_WM_STATE_ICONIC + || (data[0] == XCB_WM_STATE_WITHDRAWN && m_minimized)); } - } else { // _NET_WM_STATE can't change minimized state - if (m_lastWindowStateEvent == Qt::WindowMinimized) - newState = Qt::WindowMinimized; - } - - if (newState != Qt::WindowMinimized) { // Something else changed, get _NET_WM_STATE. - const NetWmStates states = netWmStates(); - if (states & NetWmStateFullScreen) - newState = Qt::WindowFullScreen; - else if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert)) - newState = Qt::WindowMaximized; } + if (m_minimized) + newState = Qt::WindowMinimized; + + const NetWmStates states = netWmStates(); + if (states & NetWmStateFullScreen) + newState |= Qt::WindowFullScreen; + if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert)) + newState |= Qt::WindowMaximized; // Send Window state, compress events in case other flags (modality, etc) are changed. if (m_lastWindowStateEvent != newState) { QWindowSystemInterface::handleWindowStateChanged(window(), newState); m_lastWindowStateEvent = newState; m_windowState = newState; - if (m_windowState == Qt::WindowMinimized && connection()->mouseGrabber() == this) + if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() == this) connection()->setMouseGrabber(Q_NULLPTR); } return; diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index b4d947e700..3e539337b1 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -82,7 +82,7 @@ public: void setVisible(bool visible) override; void setWindowFlags(Qt::WindowFlags flags) override; - void setWindowState(Qt::WindowState state) override; + void setWindowState(Qt::WindowStates state) override; WId winId() const override; void setParent(const QPlatformWindow *window) override; @@ -243,7 +243,7 @@ protected: xcb_sync_int64_t m_syncValue; xcb_sync_counter_t m_syncCounter = 0; - Qt::WindowState m_windowState = Qt::WindowNoState; + Qt::WindowStates m_windowState = Qt::WindowNoState; xcb_gravity_t m_gravity = XCB_GRAVITY_STATIC; @@ -253,6 +253,7 @@ protected: bool m_deferredActivation = false; bool m_embedded = false; bool m_alertState = false; + bool m_minimized = false; xcb_window_t m_netWmUserTimeWindow = XCB_NONE; QSurfaceFormat m_format; @@ -264,7 +265,8 @@ protected: QSize m_oldWindowSize; xcb_visualid_t m_visualId = 0; - int m_lastWindowStateEvent = -1; + // Last sent state. Initialized to an invalid state, on purpose. + Qt::WindowStates m_lastWindowStateEvent = Qt::WindowActive; enum SyncState { NoSyncNeeded, -- cgit v1.2.3