diff options
author | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-06-06 15:35:06 +0200 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-06-06 19:00:41 +0200 |
commit | 2a302a73613d68475e667f69b8e36ce07853c813 (patch) | |
tree | 06de55baaed993b51af517dba8f230fab749882c /src/plugins/platforms/windows/qwindowswindow.cpp | |
parent | 5505d25be972948db1621e1511b89b4144aa8bfc (diff) | |
parent | dea7110b29c5c68a5b09454c968324042ed1b607 (diff) |
Merge remote-tracking branch 'origin/dev' into wip/qt6
Change-Id: Iac12a37fa6536ebe30e6548f7c54ec0c402c9f5d
Diffstat (limited to 'src/plugins/platforms/windows/qwindowswindow.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowswindow.cpp | 347 |
1 files changed, 266 insertions, 81 deletions
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index d55545af42..74c295d155 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -134,6 +134,10 @@ static QByteArray debugWinExStyle(DWORD exStyle) rc += " WS_EX_LAYERED"; if (exStyle & WS_EX_DLGMODALFRAME) rc += " WS_EX_DLGMODALFRAME"; + if (exStyle & WS_EX_LAYOUTRTL) + rc += " WS_EX_LAYOUTRTL"; + if (exStyle & WS_EX_NOINHERITLAYOUT) + rc += " WS_EX_NOINHERITLAYOUT"; return rc; } @@ -184,6 +188,7 @@ static inline RECT RECTfromQRect(const QRect &rect) return result; } + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const RECT &r) { @@ -262,6 +267,16 @@ QDebug operator<<(QDebug d, const GUID &guid) } #endif // !QT_NO_DEBUG_STREAM +static void formatBriefRectangle(QDebug &d, const QRect &r) +{ + d << r.width() << 'x' << r.height() << Qt::forcesign << r.x() << r.y() << Qt::noforcesign; +} + +static void formatBriefMargins(QDebug &d, const QMargins &m) +{ + d << m.left() << ", " << m.top() << ", " << m.right() << ", " << m.bottom(); +} + // QTBUG-43872, for windows that do not have WS_EX_TOOLWINDOW set, WINDOWPLACEMENT // is in workspace/available area coordinates. static QPoint windowPlacementOffset(HWND hwnd, const QPoint &point) @@ -296,7 +311,7 @@ static inline QRect frameGeometry(HWND hwnd, bool topLevel) const int width = rect.right - rect.left; const int height = rect.bottom - rect.top; POINT leftTop = { rect.left, rect.top }; - ScreenToClient(parent, &leftTop); + screenToClient(parent, &leftTop); rect.left = leftTop.x; rect.top = leftTop.y; rect.right = leftTop.x + width; @@ -656,6 +671,17 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag if ((flags & Qt::MSWindowsFixedSizeDialogHint)) dialog = true; + // This causes the title bar to drawn RTL and the close button + // to be left. Note that this causes: + // - All DCs created on the Window to have RTL layout (see SetLayout) + // - ClientToScreen() and ScreenToClient() to work in reverse as well. + // - Mouse event coordinates to be mirrored. + // - Positioning of child Windows. + if (QGuiApplication::layoutDirection() == Qt::RightToLeft + && (QWindowsIntegration::instance()->options() & QWindowsIntegration::RtlEnabled) != 0) { + exStyle |= WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT; + } + // Parent: Use transient parent for top levels. if (popup) { flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent. @@ -761,6 +787,16 @@ QWindowsWindowData QPoint pos = calcPosition(w, context, invMargins); + // Mirror the position when creating on a parent in RTL mode, ditto for the obtained geometry. + int mirrorParentWidth = 0; + if (!w->isTopLevel() && QWindowsBaseWindow::isRtlLayout(parentHandle)) { + RECT rect; + GetClientRect(parentHandle, &rect); + mirrorParentWidth = rect.right; + } + if (mirrorParentWidth != 0 && pos.x() != CW_USEDEFAULT && context->frameWidth != CW_USEDEFAULT) + pos.setX(mirrorParentWidth - context->frameWidth - pos.x()); + result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16, style, pos.x(), pos.y(), @@ -768,14 +804,21 @@ QWindowsWindowData parentHandle, nullptr, appinst, nullptr); qCDebug(lcQpaWindows).nospace() << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " - << context->obtainedGeometry << ' ' << context->margins; + << context->obtainedPos << context->obtainedSize << ' ' << context->margins; if (!result.hwnd) { qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__); return result; } - result.geometry = context->obtainedGeometry; + if (mirrorParentWidth != 0) { + context->obtainedPos.setX(mirrorParentWidth - context->obtainedSize.width() + - context->obtainedPos.x()); + } + + QRect obtainedGeometry(context->obtainedPos, context->obtainedSize); + + result.geometry = obtainedGeometry; result.fullFrameMargins = context->margins; result.embedded = embedded; result.hasFrame = hasFrame; @@ -859,35 +902,78 @@ static QSize toNativeSizeConstrained(QSize dip, const QWindow *w) \ingroup qt-lighthouse-win */ -QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) : - minimumSize(toNativeSizeConstrained(w->minimumSize(), w)), - maximumSize(toNativeSizeConstrained(w->maximumSize(), w)), - customMargins(cm) +QMargins QWindowsGeometryHint::frameOnPrimaryScreen(DWORD style, DWORD exStyle) { + RECT rect = {0,0,0,0}; + style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs. + if (AdjustWindowRectEx(&rect, style, FALSE, exStyle) == FALSE) + qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__); + const QMargins result(qAbs(rect.left), qAbs(rect.top), + qAbs(rect.right), qAbs(rect.bottom)); + qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style=" + << Qt::showbase << Qt::hex << style << " exStyle=" << exStyle << Qt::dec << Qt::noshowbase + << ' ' << rect << ' ' << result; + return result; } -bool QWindowsGeometryHint::validSize(const QSize &s) const +QMargins QWindowsGeometryHint::frameOnPrimaryScreen(HWND hwnd) { - const int width = s.width(); - const int height = s.height(); - return width >= minimumSize.width() && width <= maximumSize.width() - && height >= minimumSize.height() && height <= maximumSize.height(); + return frameOnPrimaryScreen(DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)), + DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE))); } -QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle) +QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle, qreal dpi) { + if (QWindowsContext::user32dll.adjustWindowRectExForDpi == nullptr) + return frameOnPrimaryScreen(style, exStyle); RECT rect = {0,0,0,0}; - style &= ~(WS_OVERLAPPED); // Not permitted, see docs. - if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle)) - qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__); + style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs. + if (QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle, + unsigned(qRound(dpi))) == FALSE) { + qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__); + } const QMargins result(qAbs(rect.left), qAbs(rect.top), qAbs(rect.right), qAbs(rect.bottom)); qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style=" << Qt::showbase << Qt::hex << style << " exStyle=" << exStyle << Qt::dec << Qt::noshowbase + << " dpi=" << dpi << ' ' << rect << ' ' << result; return result; } +QMargins QWindowsGeometryHint::frame(HWND hwnd, DWORD style, DWORD exStyle) +{ + if (QWindowsScreenManager::isSingleScreen()) + return frameOnPrimaryScreen(style, exStyle); + auto screenManager = QWindowsContext::instance()->screenManager(); + auto screen = screenManager.screenForHwnd(hwnd); + if (!screen) + screen = screenManager.screens().value(0); + const auto dpi = screen ? screen->logicalDpi().first : qreal(96); + return frame(style, exStyle, dpi); +} + +// For newly created windows. +QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry, + DWORD style, DWORD exStyle) +{ + if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + return {}; + if (!QWindowsContext::user32dll.adjustWindowRectExForDpi + || QWindowsScreenManager::isSingleScreen() + || !QWindowsContext::shouldHaveNonClientDpiScaling(w)) { + return frameOnPrimaryScreen(style, exStyle); + } + qreal dpi = 96; + auto screenManager = QWindowsContext::instance()->screenManager(); + auto screen = screenManager.screenAtDp(geometry.center()); + if (!screen) + screen = screenManager.screens().value(0); + if (screen) + dpi = screen->logicalDpi().first; + return QWindowsGeometryHint::frame(style, exStyle, dpi); +} + bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result) { // NCCALCSIZE_PARAMS structure if wParam==TRUE @@ -907,36 +993,50 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co return true; } -void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const +void QWindowsGeometryHint::frameSizeConstraints(const QWindow *w, const QMargins &margins, + QSize *minimumSize, QSize *maximumSize) { - return applyToMinMaxInfo(DWORD(GetWindowLong(hwnd, GWL_STYLE)), - DWORD(GetWindowLong(hwnd, GWL_EXSTYLE)), mmi); + *minimumSize = toNativeSizeConstrained(w->minimumSize(), w); + *maximumSize = toNativeSizeConstrained(w->maximumSize(), w); + + const int maximumWidth = qMax(maximumSize->width(), minimumSize->width()); + const int maximumHeight = qMax(maximumSize->height(), minimumSize->height()); + const int frameWidth = margins.left() + margins.right(); + const int frameHeight = margins.top() + margins.bottom(); + + if (minimumSize->width() > 0) + minimumSize->rwidth() += frameWidth; + if (minimumSize->height() > 0) + minimumSize->rheight() += frameHeight; + if (maximumWidth < QWINDOWSIZE_MAX) + maximumSize->setWidth(maximumWidth + frameWidth); + if (maximumHeight < QWINDOWSIZE_MAX) + maximumSize->setHeight(maximumHeight + frameHeight); } -void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const +void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w, + const QMargins &margins, + MINMAXINFO *mmi) { + QSize minimumSize; + QSize maximumSize; + frameSizeConstraints(w, margins, &minimumSize, &maximumSize); qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min=" << minimumSize.width() << ',' << minimumSize.height() << " max=" << maximumSize.width() << ',' << maximumSize.height() + << " margins=" << margins << " in " << *mmi; - const QMargins margins = QWindowsGeometryHint::frame(style, exStyle); - const int frameWidth = margins.left() + margins.right() + customMargins.left() + customMargins.right(); - const int frameHeight = margins.top() + margins.bottom() + customMargins.top() + customMargins.bottom(); if (minimumSize.width() > 0) - mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth; + mmi->ptMinTrackSize.x = minimumSize.width(); if (minimumSize.height() > 0) - mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight; + mmi->ptMinTrackSize.y = minimumSize.height(); - const int maximumWidth = qMax(maximumSize.width(), minimumSize.width()); - const int maximumHeight = qMax(maximumSize.height(), minimumSize.height()); - if (maximumWidth < QWINDOWSIZE_MAX) - mmi->ptMaxTrackSize.x = maximumWidth + frameWidth; - if (maximumHeight < QWINDOWSIZE_MAX) - mmi->ptMaxTrackSize.y = maximumHeight + frameHeight; - qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ - << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight - << " out " << *mmi; + if (maximumSize.width() < QWINDOWSIZE_MAX) + mmi->ptMaxTrackSize.x = maximumSize.width(); + if (maximumSize.height() < QWINDOWSIZE_MAX) + mmi->ptMaxTrackSize.y = maximumSize.height(); + qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ << " out " << *mmi; } bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w) @@ -963,6 +1063,11 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w) \ingroup qt-lighthouse-win */ +bool QWindowsBaseWindow::isRtlLayout(HWND hwnd) +{ + return (GetWindowLongPtrW(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0; +} + QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w) { if (w) { @@ -996,7 +1101,7 @@ QRect QWindowsBaseWindow::geometry_sys() const QMargins QWindowsBaseWindow::frameMargins_sys() const { - return QWindowsGeometryHint::frame(style(), exStyle()); + return QWindowsGeometryHint::frame(handle(), style(), exStyle()); } void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows. @@ -1122,11 +1227,14 @@ void QWindowsForeignWindow::setVisible(bool visible) QWindowCreationContext::QWindowCreationContext(const QWindow *w, const QRect &geometryIn, const QRect &geometry, const QMargins &cm, - DWORD style_, DWORD exStyle_) : - geometryHint(w, cm), window(w), style(style_), exStyle(exStyle_), + DWORD style, DWORD exStyle) : + window(w), requestedGeometryIn(geometryIn), - requestedGeometry(geometry), obtainedGeometry(geometry), - margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm) + requestedGeometry(geometry), + obtainedPos(geometryIn.topLeft()), + obtainedSize(geometryIn.size()), + margins(QWindowsGeometryHint::frame(w, geometry, style, exStyle)), + customMargins(cm) { // Geometry of toplevels does not consider window frames. // TODO: No concept of WA_wasMoved yet that would indicate a @@ -1155,8 +1263,12 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, << " pos incl. frame=" << QWindowsGeometryHint::positionIncludesFrame(w) << " frame=" << frameWidth << 'x' << frameHeight << '+' << frameX << '+' << frameY - << " min=" << geometryHint.minimumSize << " max=" << geometryHint.maximumSize - << " custom margins=" << customMargins; + << " margins=" << margins << " custom margins=" << customMargins; +} + +void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const +{ + QWindowsGeometryHint::applyToMinMaxInfo(window, margins + customMargins, mmi); } /*! @@ -1191,7 +1303,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_cursor(new CursorHandle), m_format(aWindow->requestedFormat()) #if QT_CONFIG(vulkan) - , m_vkSurface(0) + , m_vkSurface(VK_NULL_HANDLE) #endif { QWindowsContext::instance()->addWindow(m_data.hwnd, this); @@ -1248,11 +1360,12 @@ void QWindowsWindow::initialize() // will send the message) and screen change signals of QWindow. if (w->type() != Qt::Desktop) { const Qt::WindowState state = w->windowState(); + const QRect obtainedGeometry(creationContext->obtainedPos, creationContext->obtainedSize); if (state != Qt::WindowMaximized && state != Qt::WindowFullScreen - && creationContext->requestedGeometryIn != creationContext->obtainedGeometry) { - QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(w, creationContext->obtainedGeometry); + && creationContext->requestedGeometryIn != obtainedGeometry) { + QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(w, obtainedGeometry); } - QPlatformScreen *obtainedScreen = screenForGeometry(creationContext->obtainedGeometry); + QPlatformScreen *obtainedScreen = screenForGeometry(obtainedGeometry); if (obtainedScreen && screen() != obtainedScreen) QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, obtainedScreen->screen()); } @@ -1291,14 +1404,14 @@ void QWindowsWindow::destroyWindow() QVulkanInstance *inst = window()->vulkanInstance(); if (inst) static_cast<QWindowsVulkanInstance *>(inst->handle())->destroySurface(m_vkSurface); - m_vkSurface = 0; + m_vkSurface = VK_NULL_HANDLE; } #endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) staticOpenGLContext->destroyWindowSurface(m_surface); - m_surface = 0; + m_surface = nullptr; } #endif DestroyWindow(m_data.hwnd); @@ -1672,10 +1785,57 @@ QRect QWindowsWindow::normalGeometry() const 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) : fullFrameMargins(); + const QMargins margins = fakeFullScreen + ? QWindowsGeometryHint::frame(handle(), m_savedStyle, 0) + : fullFrameMargins(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; } +static QString msgUnableToSetGeometry(const QWindowsWindow *platformWindow, + const QRect &requestedRect, + const QRect &obtainedRect, + const QMargins &fullMargins, + const QMargins &customMargins) +{ + QString result; + QDebug debug(&result); + debug.nospace(); + debug.noquote(); + const auto window = platformWindow->window(); + debug << "Unable to set geometry "; + formatBriefRectangle(debug, requestedRect); + debug << " (frame: "; + formatBriefRectangle(debug, requestedRect + fullMargins); + debug << ") on " << window->metaObject()->className() << "/\"" + << window->objectName() << "\" on \"" << window->screen()->name() + << "\". Resulting geometry: "; + formatBriefRectangle(debug, obtainedRect); + debug << " (frame: "; + formatBriefRectangle(debug, obtainedRect + fullMargins); + debug << ") margins: "; + formatBriefMargins(debug, fullMargins); + if (!customMargins.isNull()) { + debug << " custom margin: "; + formatBriefMargins(debug, customMargins); + } + const auto minimumSize = window->minimumSize(); + const bool hasMinimumSize = !minimumSize.isEmpty(); + if (hasMinimumSize) + debug << " minimum size: " << minimumSize.width() << 'x' << minimumSize.height(); + const auto maximumSize = window->maximumSize(); + const bool hasMaximumSize = maximumSize.width() != QWINDOWSIZE_MAX || maximumSize.height() != QWINDOWSIZE_MAX; + if (hasMaximumSize) + debug << " maximum size: " << maximumSize.width() << 'x' << maximumSize.height(); + if (hasMinimumSize || hasMaximumSize) { + MINMAXINFO minmaxInfo; + memset(&minmaxInfo, 0, sizeof(minmaxInfo)); + platformWindow->getSizeHints(&minmaxInfo); + debug << ' ' << minmaxInfo; + } + debug << ')'; + return result; +} + void QWindowsWindow::setGeometry(const QRect &rectIn) { QRect rect = rectIn; @@ -1695,21 +1855,10 @@ void QWindowsWindow::setGeometry(const QRect &rectIn) setGeometry_sys(rect); clearFlag(WithinSetGeometry); if (m_data.geometry != rect && (isVisible() || QLibraryInfo::isDebugBuild())) { - qWarning("%s: Unable to set geometry %dx%d+%d+%d on %s/'%s'." - " Resulting geometry: %dx%d+%d+%d " - "(frame: %d, %d, %d, %d, custom margin: %d, %d, %d, %d" - ", minimum size: %dx%d, maximum size: %dx%d).", - __FUNCTION__, - rect.width(), rect.height(), rect.x(), rect.y(), - window()->metaObject()->className(), qPrintable(window()->objectName()), - m_data.geometry.width(), m_data.geometry.height(), - m_data.geometry.x(), m_data.geometry.y(), - m_data.fullFrameMargins.left(), m_data.fullFrameMargins.top(), - m_data.fullFrameMargins.right(), m_data.fullFrameMargins.bottom(), - m_data.customMargins.left(), m_data.customMargins.top(), - m_data.customMargins.right(), m_data.customMargins.bottom(), - window()->minimumWidth(), window()->minimumHeight(), - window()->maximumWidth(), window()->maximumHeight()); + const auto warning = + msgUnableToSetGeometry(this, rectIn, m_data.geometry, + m_data.fullFrameMargins, m_data.customMargins); + qWarning("%s: %s", __FUNCTION__, qPrintable(warning)); } } else { QPlatformWindow::setGeometry(rect); @@ -1753,27 +1902,41 @@ void QWindowsWindow::handleResized(int wParam) } } -void QWindowsWindow::checkForScreenChanged() +static inline bool equalDpi(const QDpi &d1, const QDpi &d2) +{ + return qFuzzyCompare(d1.first, d2.first) && qFuzzyCompare(d1.second, d2.second); +} + +void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode) { - if (parent()) + if (parent() || QWindowsScreenManager::isSingleScreen()) return; QPlatformScreen *currentScreen = screen(); - const auto &screenManager = QWindowsContext::instance()->screenManager(); - const QWindowsScreen *newScreen = screenManager.screenForHwnd(m_data.hwnd); - if (newScreen != nullptr && newScreen != currentScreen) { - qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ - << ' ' << window() << " \"" << currentScreen->name() - << "\"->\"" << newScreen->name() << '"'; - setFlag(SynchronousGeometryChangeEvent); - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + const QWindowsScreen *newScreen = + QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd); + if (newScreen == nullptr || newScreen == currentScreen) + return; + // For screens with different DPI: postpone until WM_DPICHANGE + if (mode == FromGeometryChange + && !equalDpi(currentScreen->logicalDpi(), newScreen->logicalDpi())) { + return; } + qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ + << ' ' << window() << " \"" << currentScreen->name() + << "\"->\"" << newScreen->name() << '"'; + if (mode == FromGeometryChange) + setFlag(SynchronousGeometryChangeEvent); + updateFullFrameMargins(); + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); } void QWindowsWindow::handleGeometryChange() { const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); + if (testFlag(WithinDpiChanged)) + return; // QGuiApplication will send resize QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive // expose events when shrinking, synthesize. @@ -1819,7 +1982,16 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE; result = SetWindowPlacement(hwnd, &windowPlacement); } else { - result = MoveWindow(hwnd, frameGeometry.x(), frameGeometry.y(), + int x = frameGeometry.x(); + if (!window()->isTopLevel()) { + const HWND parentHandle = GetParent(hwnd); + if (isRtlLayout(parentHandle)) { + RECT rect; + GetClientRect(parentHandle, &rect); + x = rect.right - frameGeometry.width() - x; + } + } + result = MoveWindow(hwnd, x, frameGeometry.y(), frameGeometry.width(), frameGeometry.height(), true); } qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << window() @@ -1835,8 +2007,11 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const HDC QWindowsWindow::getDC() { - if (!m_hdc) + if (!m_hdc) { m_hdc = GetDC(handle()); + if (QGuiApplication::layoutDirection() == Qt::RightToLeft) + SetLayout(m_hdc, 0); // Clear RTL layout + } return m_hdc; } @@ -1876,6 +2051,9 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, { if (message == WM_ERASEBKGND) // Backing store - ignored. return true; + // QTBUG-75455: Suppress WM_PAINT sent to invisible windows when setting WS_EX_LAYERED + if (!window()->isVisible() && (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) != 0) + return false; // Ignore invalid update bounding rectangles RECT updateRect; if (!GetUpdateRect(m_data.hwnd, &updateRect, FALSE)) @@ -2233,6 +2411,15 @@ void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins) } } +void QWindowsWindow::updateFullFrameMargins() +{ + // Normally obtained from WM_NCCALCSIZE + const auto systemMargins = testFlag(DisableNonClientScaling) + ? QWindowsGeometryHint::frameOnPrimaryScreen(m_data.hwnd) + : frameMargins_sys(); + setFullFrameMargins(systemMargins + m_data.customMargins); +} + QMargins QWindowsWindow::frameMargins() const { QMargins result = fullFrameMargins(); @@ -2443,10 +2630,8 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const { // We don't apply the min/max size hint as we change the dpi, because we did not adjust the // QScreen of the window yet so we don't have the min/max with the right ratio - if (!testFlag(QWindowsWindow::WithinDpiChanged)) { - const QWindowsGeometryHint hint(window(), m_data.customMargins); - hint.applyToMinMaxInfo(m_data.hwnd, mmi); - } + if (!testFlag(QWindowsWindow::WithinDpiChanged)) + QWindowsGeometryHint::applyToMinMaxInfo(window(), fullFrameMargins(), mmi); // This block fixes QTBUG-8361, QTBUG-4362: Frameless/title-less windows shouldn't cover the // taskbar when maximized @@ -2758,14 +2943,14 @@ void QWindowsWindow::invalidateSurface() QVulkanInstance *inst = window()->vulkanInstance(); if (inst) static_cast<QWindowsVulkanInstance *>(inst->handle())->destroySurface(m_vkSurface); - m_vkSurface = 0; + m_vkSurface = VK_NULL_HANDLE; } #endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) staticOpenGLContext->destroyWindowSurface(m_surface); - m_surface = 0; + m_surface = nullptr; } #endif // QT_NO_OPENGL } |