From 3e942c3dc8955be577079fbc028ce216e1c594b2 Mon Sep 17 00:00:00 2001 From: SineStriker <55847490+SineStriker@users.noreply.github.com> Date: 周二, 11 2月 2025 19:07:53 +0800 Subject: [PATCH] Fix numerous bugs (#162) --- src/core/shared/qwkwindowsextra_p.h | 169 +++++++++++++++++++++++++++++++------------------------ 1 files changed, 95 insertions(+), 74 deletions(-) diff --git a/src/core/shared/qwkwindowsextra_p.h b/src/core/shared/qwkwindowsextra_p.h index 0b24382..8fdc86e 100644 --- a/src/core/shared/qwkwindowsextra_p.h +++ b/src/core/shared/qwkwindowsextra_p.h @@ -1,3 +1,7 @@ +// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware) +// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao) +// SPDX-License-Identifier: Apache-2.0 + #ifndef QWKWINDOWSEXTRA_P_H #define QWKWINDOWSEXTRA_P_H @@ -16,12 +20,12 @@ #include <QWKCore/qwindowkit_windows.h> -#include <QtCore/private/qsystemlibrary_p.h> -#include <QtCore/private/qwinregistry_p.h> - +#include <QtCore/QtMath> #include <QtGui/QGuiApplication> #include <QtGui/QStyleHints> #include <QtGui/QPalette> + +#include <QtCore/private/qsystemlibrary_p.h> // Don't include this header in any header files. @@ -132,12 +136,14 @@ }; using PWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA *; - enum PREFERRED_APP_MODE - { - PAM_DEFAULT = 0, // Default behavior on systems before Win10 1809. It indicates the application doesn't support dark mode at all. - PAM_AUTO = 1, // Available since Win10 1809, let system decide whether to enable dark mode or not. - PAM_DARK = 2, // Available since Win10 1903, force dark mode regardless of the system theme. - PAM_LIGHT = 3, // Available since Win10 1903, force light mode regardless of the system theme. + enum PREFERRED_APP_MODE { + PAM_DEFAULT = 0, // Default behavior on systems before Win10 1809. It indicates the + // application doesn't support dark mode at all. + PAM_AUTO = + 1, // Available since Win10 1809, let system decide whether to enable dark mode or not. + PAM_DARK = 2, // Available since Win10 1903, force dark mode regardless of the system theme. + PAM_LIGHT = + 3, // Available since Win10 1903, force light mode regardless of the system theme. PAM_MAX = 4 }; @@ -155,7 +161,7 @@ struct DynamicApis { static const DynamicApis &instance() { - static const DynamicApis inst{}; + static const DynamicApis inst; return inst; } @@ -163,17 +169,14 @@ DYNAMIC_API_DECLARE(DwmFlush); DYNAMIC_API_DECLARE(DwmIsCompositionEnabled); - DYNAMIC_API_DECLARE(DwmGetCompositionTimingInfo); DYNAMIC_API_DECLARE(DwmGetWindowAttribute); DYNAMIC_API_DECLARE(DwmSetWindowAttribute); DYNAMIC_API_DECLARE(DwmExtendFrameIntoClientArea); DYNAMIC_API_DECLARE(DwmEnableBlurBehindWindow); DYNAMIC_API_DECLARE(GetDpiForWindow); DYNAMIC_API_DECLARE(GetSystemMetricsForDpi); + DYNAMIC_API_DECLARE(AdjustWindowRectExForDpi); DYNAMIC_API_DECLARE(GetDpiForMonitor); - DYNAMIC_API_DECLARE(timeGetDevCaps); - DYNAMIC_API_DECLARE(timeBeginPeriod); - DYNAMIC_API_DECLARE(timeEndPeriod); #undef DYNAMIC_API_DECLARE @@ -193,6 +196,7 @@ DYNAMIC_API_RESOLVE(user32, GetDpiForWindow); DYNAMIC_API_RESOLVE(user32, GetSystemMetricsForDpi); DYNAMIC_API_RESOLVE(user32, SetWindowCompositionAttribute); + DYNAMIC_API_RESOLVE(user32, AdjustWindowRectExForDpi); QSystemLibrary shcore(QStringLiteral("shcore")); DYNAMIC_API_RESOLVE(shcore, GetDpiForMonitor); @@ -200,16 +204,10 @@ QSystemLibrary dwmapi(QStringLiteral("dwmapi")); DYNAMIC_API_RESOLVE(dwmapi, DwmFlush); DYNAMIC_API_RESOLVE(dwmapi, DwmIsCompositionEnabled); - DYNAMIC_API_RESOLVE(dwmapi, DwmGetCompositionTimingInfo); DYNAMIC_API_RESOLVE(dwmapi, DwmGetWindowAttribute); DYNAMIC_API_RESOLVE(dwmapi, DwmSetWindowAttribute); DYNAMIC_API_RESOLVE(dwmapi, DwmExtendFrameIntoClientArea); DYNAMIC_API_RESOLVE(dwmapi, DwmEnableBlurBehindWindow); - - QSystemLibrary winmm(QStringLiteral("winmm")); - DYNAMIC_API_RESOLVE(winmm, timeGetDevCaps); - DYNAMIC_API_RESOLVE(winmm, timeBeginPeriod); - DYNAMIC_API_RESOLVE(winmm, timeEndPeriod); #undef DYNAMIC_API_RESOLVE @@ -228,101 +226,101 @@ ~DynamicApis() = default; - Q_DISABLE_COPY_MOVE(DynamicApis) + Q_DISABLE_COPY(DynamicApis) }; } - static inline constexpr bool operator==(const POINT &lhs, const POINT &rhs) noexcept { + inline constexpr bool operator==(const POINT &lhs, const POINT &rhs) noexcept { return ((lhs.x == rhs.x) && (lhs.y == rhs.y)); } - static inline constexpr bool operator!=(const POINT &lhs, const POINT &rhs) noexcept { + inline constexpr bool operator!=(const POINT &lhs, const POINT &rhs) noexcept { return !operator==(lhs, rhs); } - static inline constexpr bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept { + inline constexpr bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept { return ((lhs.cx == rhs.cx) && (lhs.cy == rhs.cy)); } - static inline constexpr bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept { + inline constexpr bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept { return !operator==(lhs, rhs); } - static inline constexpr bool operator>(const SIZE &lhs, const SIZE &rhs) noexcept { + inline constexpr bool operator>(const SIZE &lhs, const SIZE &rhs) noexcept { return ((lhs.cx * lhs.cy) > (rhs.cx * rhs.cy)); } - static inline constexpr bool operator>=(const SIZE &lhs, const SIZE &rhs) noexcept { + inline constexpr bool operator>=(const SIZE &lhs, const SIZE &rhs) noexcept { return (operator>(lhs, rhs) || operator==(lhs, rhs)); } - static inline constexpr bool operator<(const SIZE &lhs, const SIZE &rhs) noexcept { + inline constexpr bool operator<(const SIZE &lhs, const SIZE &rhs) noexcept { return (operator!=(lhs, rhs) && !operator>(lhs, rhs)); } - static inline constexpr bool operator<=(const SIZE &lhs, const SIZE &rhs) noexcept { + inline constexpr bool operator<=(const SIZE &lhs, const SIZE &rhs) noexcept { return (operator<(lhs, rhs) || operator==(lhs, rhs)); } - static inline constexpr bool operator==(const RECT &lhs, const RECT &rhs) noexcept { + inline constexpr bool operator==(const RECT &lhs, const RECT &rhs) noexcept { return ((lhs.left == rhs.left) && (lhs.top == rhs.top) && (lhs.right == rhs.right) && (lhs.bottom == rhs.bottom)); } - static inline constexpr bool operator!=(const RECT &lhs, const RECT &rhs) noexcept { + inline constexpr bool operator!=(const RECT &lhs, const RECT &rhs) noexcept { return !operator==(lhs, rhs); } - static inline constexpr QPoint point2qpoint(const POINT &point) { + inline constexpr QPoint point2qpoint(const POINT &point) { return QPoint{int(point.x), int(point.y)}; } - static inline constexpr POINT qpoint2point(const QPoint &point) { + inline constexpr POINT qpoint2point(const QPoint &point) { return POINT{LONG(point.x()), LONG(point.y())}; } - static inline constexpr QSize size2qsize(const SIZE &size) { + inline constexpr QSize size2qsize(const SIZE &size) { return QSize{int(size.cx), int(size.cy)}; } - static inline constexpr SIZE qsize2size(const QSize &size) { + inline constexpr SIZE qsize2size(const QSize &size) { return SIZE{LONG(size.width()), LONG(size.height())}; } - static inline constexpr QRect rect2qrect(const RECT &rect) { + inline constexpr QRect rect2qrect(const RECT &rect) { return QRect{ QPoint{int(rect.left), int(rect.top) }, QSize{int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect))} }; } - static inline constexpr RECT qrect2rect(const QRect &qrect) { + inline constexpr RECT qrect2rect(const QRect &qrect) { return RECT{LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom())}; } - static inline constexpr QMargins margins2qmargins(const MARGINS &margins) { + inline constexpr QMargins margins2qmargins(const MARGINS &margins) { return {margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight}; } - static inline constexpr MARGINS qmargins2margins(const QMargins &qmargins) { + inline constexpr MARGINS qmargins2margins(const QMargins &qmargins) { return {qmargins.left(), qmargins.right(), qmargins.top(), qmargins.bottom()}; } - static inline /*constexpr*/ QString hwnd2str(const WId windowId) { + inline /*constexpr*/ QString hwnd2str(const WId windowId) { // NULL handle is allowed here. return QLatin1String("0x") + QString::number(windowId, 16).toUpper().rightJustified(8, u'0'); } - static inline /*constexpr*/ QString hwnd2str(HWND hwnd) { + inline /*constexpr*/ QString hwnd2str(HWND hwnd) { // NULL handle is allowed here. return hwnd2str(reinterpret_cast<WId>(hwnd)); } - static inline bool isDwmCompositionEnabled() { + inline bool isDwmCompositionEnabled() { if (isWin8OrGreater()) { return true; } @@ -334,8 +332,8 @@ return SUCCEEDED(apis.pDwmIsCompositionEnabled(&enabled)) && enabled; } - static inline bool isWindowFrameBorderColorized() { - QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); + inline bool isWindowFrameBorderColorized() { + WindowsRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); if (!registry.isValid()) { return false; } @@ -346,18 +344,21 @@ return value.first; } - static inline bool isHighContrastModeEnabled() { + inline bool isHighContrastModeEnabled() { HIGHCONTRASTW hc{}; hc.cbSize = sizeof(hc); ::SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(hc), &hc, FALSE); return (hc.dwFlags & HCF_HIGHCONTRASTON); } - static inline bool isDarkThemeActive() { + inline bool isDarkThemeActive() { + if (!isWin101809OrGreater()) { + return false; + } #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) return QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark; #else - QWinRegistryKey registry( + WindowsRegistryKey registry( HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"); if (!registry.isValid()) { return false; @@ -370,25 +371,23 @@ #endif } - static inline bool isDarkWindowFrameEnabled(HWND hwnd) { + inline bool isDarkWindowFrameEnabled(HWND hwnd) { + if (!isWin101809OrGreater()) { + return false; + } BOOL enabled = FALSE; const DynamicApis &apis = DynamicApis::instance(); - if (SUCCEEDED(apis.pDwmGetWindowAttribute(hwnd, _DWMWA_USE_IMMERSIVE_DARK_MODE, &enabled, - sizeof(enabled)))) { - return enabled; - } else if (SUCCEEDED(apis.pDwmGetWindowAttribute(hwnd, - _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, - &enabled, sizeof(enabled)))) { - return enabled; - } - return false; + const auto attr = isWin1020H1OrGreater() ? _DWMWA_USE_IMMERSIVE_DARK_MODE + : _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1; + return SUCCEEDED(apis.pDwmGetWindowAttribute(hwnd, attr, &enabled, sizeof(enabled))) && + enabled; } - static inline QColor getAccentColor() { + inline QColor getAccentColor() { #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) return QGuiApplication::palette().color(QPalette::Accent); #else - QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); + WindowsRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); if (!registry.isValid()) { return {}; } @@ -406,9 +405,9 @@ #endif } - static inline quint32 getDpiForWindow(HWND hwnd) { + inline quint32 getDpiForWindow(HWND hwnd) { const DynamicApis &apis = DynamicApis::instance(); - if (apis.pGetDpiForWindow) { // Win10 + if (apis.pGetDpiForWindow) { // Win10 return apis.pGetDpiForWindow(hwnd); } else if (apis.pGetDpiForMonitor) { // Win8.1 HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); @@ -425,33 +424,55 @@ } } - static inline quint32 getSystemMetricsForDpi(int index, quint32 dpi) { + inline quint32 getSystemMetricsForDpi(int index, quint32 dpi) { const DynamicApis &apis = DynamicApis::instance(); if (apis.pGetSystemMetricsForDpi) { - return ::GetSystemMetricsForDpi(index, dpi); + return apis.pGetSystemMetricsForDpi(index, dpi); } - return ::GetSystemMetrics(index); - } - - static inline quint32 getWindowFrameBorderThickness(HWND hwnd) { - const DynamicApis &apis = DynamicApis::instance(); - if (UINT result = 0; SUCCEEDED(apis.pDwmGetWindowAttribute( - hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &result, sizeof(result)))) { + const int result = ::GetSystemMetrics(index); + // GetSystemMetrics() always give you scaled value. + if (dpi != USER_DEFAULT_SCREEN_DPI) { return result; } - return getSystemMetricsForDpi(SM_CXBORDER, getDpiForWindow(hwnd)); + const qreal dpr = qreal(dpi) / qreal(USER_DEFAULT_SCREEN_DPI); + // ### Not sure how Windows itself rounds non-integer value. + return qFloor(qreal(result) / dpr); } - static inline quint32 getResizeBorderThickness(HWND hwnd) { + inline quint32 getWindowFrameBorderThickness(HWND hwnd) { + const DynamicApis &apis = DynamicApis::instance(); + if (isWin11OrGreater()) { + UINT result = 0; + if (SUCCEEDED(apis.pDwmGetWindowAttribute(hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, + &result, sizeof(result)))) { + return result; + } + } + if (isWin10OrGreater()) { + const quint32 dpi = getDpiForWindow(hwnd); + // When DPI is 96, it should be 1px. + return getSystemMetricsForDpi(SM_CXBORDER, dpi); + } + // There's no such thing (a visible frame border line) before Win10. + return 0; + } + + inline quint32 getResizeBorderThickness(HWND hwnd) { const quint32 dpi = getDpiForWindow(hwnd); + // When DPI is 96, SM_CXSIZEFRAME is 4px, SM_CXPADDEDBORDER is also 4px, + // so the result should be 8px. This result won't be affected by OS version, + // it's 8px in Win7, and so in Win11. return getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); } - static inline quint32 getTitleBarHeight(HWND hwnd) { + inline quint32 getTitleBarHeight(HWND hwnd) { const quint32 dpi = getDpiForWindow(hwnd); + // When DPI is 96, SM_CYCAPTION is 23px, so the result should be 31px. + // However, according to latest MS design manual, the title bar height + // should be 32px, maybe there's some rounding issue. return getSystemMetricsForDpi(SM_CYCAPTION, dpi) + - getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + + getSystemMetricsForDpi(SM_CYSIZEFRAME, dpi) + getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi); } -- Gitblit v1.9.1