From 68608585a5921bf123a278e14490e323febaa156 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sat, 22 Jun 2024 07:52:12 +0200 Subject: [PATCH] Windows style: paint treeview indicators with correct dpr The QTreeView indicators in windows style are drawn with the help of windows themes. Sadly, indicators have to be drawn in the explorer style. This was already done correctly for visible windows. Hidden windows, however, using this drawing method, were not dpi-aware. As a consequence, the dpi of the primary screen was used for drawing. This lead to wrong results on a second monitor with a different dpi. Create a hidden window for every screen and use this for the painting instead. The fix can't be covered by an autotest. It will result in baseline test mismatches, which must be accepted as new baselines. Fixes: QTBUG-126533 Change-Id: Ie86cdb69f4cef1b293a5ac65541e5ada12959180 Reviewed-by: Axel Spoerl (cherry picked from commit 7f08822c499f624246d3f4c35dd97a7ba81d85ae) Reviewed-by: Qt Cherry-pick Bot --- .../modernwindows/qwindowsthemedata.cpp | 2 +- .../modernwindows/qwindowsvistastyle.cpp | 38 ++++++++++--------- .../modernwindows/qwindowsvistastyle_p_p.h | 8 ++-- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/plugins/styles/modernwindows/qwindowsthemedata.cpp b/src/plugins/styles/modernwindows/qwindowsthemedata.cpp index 44569e054d7..c13fe596799 100644 --- a/src/plugins/styles/modernwindows/qwindowsthemedata.cpp +++ b/src/plugins/styles/modernwindows/qwindowsthemedata.cpp @@ -23,7 +23,7 @@ HTHEME QWindowsThemeData::handle() return nullptr; if (!htheme) - htheme = QWindowsVistaStylePrivate::createTheme(theme, QWindowsVistaStylePrivate::winId(widget)); + htheme = QWindowsVistaStylePrivate::createTheme(theme, widget); return htheme; } diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp index beee1d6f313..208420d7e8b 100644 --- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp +++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp @@ -54,7 +54,7 @@ static const int windowsRightBorder = 15; // right border on windows // QWindowsVistaStylePrivate ------------------------------------------------------------------------- // Static initializations -HWND QWindowsVistaStylePrivate::m_vistaTreeViewHelper = nullptr; +QVarLengthFlatMap QWindowsVistaStylePrivate::m_vistaTreeViewHelpers; bool QWindowsVistaStylePrivate::useVistaTheme = false; Q_CONSTINIT QBasicAtomicInt QWindowsVistaStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting @@ -100,7 +100,7 @@ static inline Qt::Orientation progressBarOrientation(const QStyleOption *option * a non-visible window handle, open the theme on it and insert it into * the cache so that it is found by QWindowsThemeData::handle() first. */ -static inline HWND createTreeViewHelperWindow() +static inline HWND createTreeViewHelperWindow(const QScreen *screen) { using QWindowsApplication = QNativeInterface::Private::QWindowsApplication; @@ -108,6 +108,10 @@ static inline HWND createTreeViewHelperWindow() if (auto nativeWindowsApp = dynamic_cast(QGuiApplicationPrivate::platformIntegration())) result = nativeWindowsApp->createMessageWindow(QStringLiteral("QTreeViewThemeHelperWindowClass"), QStringLiteral("QTreeViewThemeHelperWindow")); + const auto topLeft = screen->geometry().topLeft(); + // make it a top-level window and move it the the correct screen to paint with the correct dpr later on + SetParent(result, NULL); + MoveWindow(result, topLeft.x(), topLeft.y(), 10, 10, FALSE); return result; } @@ -257,30 +261,26 @@ int QWindowsVistaStylePrivate::fixedPixelMetric(QStyle::PixelMetric pm) return QWindowsVistaStylePrivate::InvalidMetric; } -bool QWindowsVistaStylePrivate::initVistaTreeViewTheming() +bool QWindowsVistaStylePrivate::initVistaTreeViewTheming(const QScreen *screen) { - if (m_vistaTreeViewHelper) + if (m_vistaTreeViewHelpers.contains(screen)) return true; - - m_vistaTreeViewHelper = createTreeViewHelperWindow(); - if (!m_vistaTreeViewHelper) { - qWarning("Unable to create the treeview helper window."); - return false; - } - if (FAILED(SetWindowTheme(m_vistaTreeViewHelper, L"explorer", nullptr))) { + HWND helper = createTreeViewHelperWindow(screen); + if (FAILED(SetWindowTheme(helper, L"explorer", nullptr))) + { qErrnoWarning("SetWindowTheme() failed."); cleanupVistaTreeViewTheming(); return false; } + m_vistaTreeViewHelpers.insert(screen, helper); return true; } void QWindowsVistaStylePrivate::cleanupVistaTreeViewTheming() { - if (m_vistaTreeViewHelper) { - DestroyWindow(m_vistaTreeViewHelper); - m_vistaTreeViewHelper = nullptr; - } + for (auto it = m_vistaTreeViewHelpers.begin(); it != m_vistaTreeViewHelpers.end(); ++it) + DestroyWindow(it.value()); + m_vistaTreeViewHelpers.clear(); } /* \internal @@ -294,10 +294,12 @@ void QWindowsVistaStylePrivate::cleanupHandleMap() QWindowsVistaStylePrivate::cleanupVistaTreeViewTheming(); } -HTHEME QWindowsVistaStylePrivate::createTheme(int theme, HWND hwnd) +HTHEME QWindowsVistaStylePrivate::createTheme(int theme, const QWidget *widget) { - if (theme == VistaTreeViewTheme && QWindowsVistaStylePrivate::initVistaTreeViewTheming()) - hwnd = QWindowsVistaStylePrivate::m_vistaTreeViewHelper; + const QScreen *screen = widget ? widget->screen() : qApp->primaryScreen(); + HWND hwnd = QWindowsVistaStylePrivate::winId(widget); + if (theme == VistaTreeViewTheme && QWindowsVistaStylePrivate::initVistaTreeViewTheming(screen)) + hwnd = QWindowsVistaStylePrivate::m_vistaTreeViewHelpers.value(screen); return QWindowsThemeCache::createTheme(theme, hwnd); } diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h index 053e98b68dd..506a097b2b2 100644 --- a/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h +++ b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #if QT_CONFIG(pushbutton) #include @@ -114,7 +114,7 @@ public: ~QWindowsVistaStylePrivate() { cleanup(); } - static HTHEME createTheme(int theme, HWND hwnd); + static HTHEME createTheme(int theme, const QWidget *widget); static QString themeName(int theme); static bool isItemViewDelegateLineEdit(const QWidget *widget); static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr); @@ -154,7 +154,7 @@ public: bool transitionsEnabled() const; private: - static bool initVistaTreeViewTheming(); + static bool initVistaTreeViewTheming(const QScreen *screen); static void cleanupVistaTreeViewTheming(); static QBasicAtomicInt ref; @@ -168,7 +168,7 @@ private: int bufferW = 0; int bufferH = 0; - static HWND m_vistaTreeViewHelper; + static QVarLengthFlatMap m_vistaTreeViewHelpers; }; QT_END_NAMESPACE