From bbd6cbd71c7ff4df3d141383d090a4bdc2459a48 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Sun, 5 Mar 2023 15:52:13 +0100 Subject: windows: Re-apply mask when DPI changes, to account for new scale factor When the DPI of a window changes due to being moved to another screen, or the current screen reconfiguring, the mask we've set earlier is no longer correct, as the mask was set based on the original screen's scale factor and in relation to the former platform geometry of the window, which now has changed. Like the geometry of a QWindow, the mask is expressed by the user in the QtGui coordinate system, so it's the platform's job to transform this into the platform coordinate system and update it when needed. Add a manual test that users a QWidget and a Q(Raster)Window side by side. There's still an issue with the screen change being triggered to early, via QWindow::setGeometry, instead of when the window has actually moved to the new screen, resulting in the paint event flushing to a window and backingstore that is in the wrong state, but this requires further research to fix. Task-number: QTBUG-97642 Pick-to: 6.5 6.2 Done-with: Volker Hilsheimer Change-Id: I7ab2d267fbaf6ac32b507d05a418eb025b354a0b Reviewed-by: Volker Hilsheimer --- src/plugins/platforms/windows/qwindowswindow.cpp | 4 + tests/manual/CMakeLists.txt | 1 + tests/manual/windowmask/CMakeLists.txt | 14 +++ tests/manual/windowmask/main.cpp | 124 +++++++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 tests/manual/windowmask/CMakeLists.txt create mode 100644 tests/manual/windowmask/main.cpp diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index d0107145af..c26e3bc1a8 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2011,6 +2011,10 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam) prcNewWindow->right - prcNewWindow->left, prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE); } + + // Re-apply mask now that we have a new DPI, which have resulted in + // a new scale factor. + setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window())); } void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd) diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt index 71dd87f575..abe9ac4235 100644 --- a/tests/manual/CMakeLists.txt +++ b/tests/manual/CMakeLists.txt @@ -64,6 +64,7 @@ endif() add_subdirectory(xmlstreamlint) add_subdirectory(shortcuts) add_subdirectory(dialogs) +add_subdirectory(windowmask) add_subdirectory(windowtransparency) add_subdirectory(unc) add_subdirectory(qtabbar) diff --git a/tests/manual/windowmask/CMakeLists.txt b/tests/manual/windowmask/CMakeLists.txt new file mode 100644 index 0000000000..e1417bedbe --- /dev/null +++ b/tests/manual/windowmask/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## windowmask Binary: +##################################################################### + +qt_internal_add_manual_test(windowmask + SOURCES + main.cpp + LIBRARIES + Qt::Gui + Qt::Widgets +) diff --git a/tests/manual/windowmask/main.cpp b/tests/manual/windowmask/main.cpp new file mode 100644 index 0000000000..d6588caba7 --- /dev/null +++ b/tests/manual/windowmask/main.cpp @@ -0,0 +1,124 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include + +template +class Circle : public Paintable +{ +public: + using Paintable::setMinimumSize; + using Paintable::setMaximumSize; + using Paintable::width; + using Paintable::height; + using Paintable::screen; + using Paintable::devicePixelRatio; + using Paintable::metaObject; + using Paintable::setMask; + using Paintable::frameGeometry; + using Paintable::setPosition; + using Paintable::startSystemMove; + using Paintable::setFlags; + using Paintable::requestUpdate; + + Circle() + { + setMinimumSize({200, 200}); + setMaximumSize({200, 200}); + setFlags(Qt::Window | Qt::FramelessWindowHint); + } + +protected: + void paintEvent(QPaintEvent *) override + { + qWarning() << "Painting into a" << this << "with DPR" << devicePixelRatio() + << "on a screen with DPR" << screen()->devicePixelRatio(); + QPainter painter(static_cast(this)); + painter.fillRect(0, 0, width(), height(), devicePixelRatio() == 1 ? Qt::red : Qt::green); + painter.setPen(QPen(Qt::black, 5)); + painter.drawRect(10, 10, width() - 20, height() - 20); + painter.drawText(0, 0, width(), height(), Qt::AlignHCenter | Qt::AlignVCenter, metaObject()->className()); + } + void mousePressEvent(QMouseEvent *event) override + { + if (event->button() == Qt::LeftButton) { + if (event->modifiers() & Qt::ControlModifier) + requestUpdate(); + else if (event->modifiers() & Qt::AltModifier) + updateMask(); + else if (event->modifiers() & Qt::ShiftModifier && startSystemMove()) + dragPosition = {}; + else + dragPosition = event->globalPosition() - frameGeometry().topLeft(); + } + } + void mouseMoveEvent(QMouseEvent *event) override + { + if (event->buttons() & Qt::LeftButton && !dragPosition.isNull()) + setPosition((event->globalPosition() - dragPosition).toPoint()); + } + void resizeEvent(QResizeEvent *) override + { + updateMask(); + } + + void updateMask() + { + int side = qMin(width(), height()); + QRegion maskedRegion(width() / 2 - side / 2, height() / 2 - side / 2, side, + side, QRegion::Ellipse); + qDebug() << "Updating mask for" << this << "to" << maskedRegion.boundingRect(); + setMask(maskedRegion); + } + + QPointF dragPosition; +}; + +class WindowLikeWidget : public QWidget +{ +public: + void setPosition(const QPoint &point) { QWidget::move(point); } + bool startSystemMove() { return windowHandle()->startSystemMove(); } + void setFlags(Qt::WindowFlags flags) { setWindowFlags(flags); } + void requestUpdate() { update(); } +}; + +class Widget : public Circle +{ +public: + Widget() + { + setAttribute(Qt::WA_TranslucentBackground); + } +}; + +class Window : public Circle +{ +}; + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + Widget widget; + widget.show(); + + Window window; + window.show(); + + auto dumpScreenData = [](QScreen *screen){ + qDebug() << "- name:" << screen->name(); + qDebug() << "- dpr :" << screen->devicePixelRatio(); + }; + + QObject::connect(widget.windowHandle(), &QWindow::screenChanged, &widget, [&]{ + qDebug() << "Screen changed for" << &widget; + dumpScreenData(widget.screen()); + }); + QObject::connect(&window, &QWindow::screenChanged, &window, [&]{ + qDebug() << "Screen changed for" << &window; + dumpScreenData(window.screen()); + }); + + return app.exec(); +} -- cgit v1.2.1