From af6d3c7380b68f0ed035c2414dc2ff8bdb2554db Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Thu, 20 Oct 2022 14:15:11 +0800 Subject: [PATCH] win: minor tweaks 1. Avoid name collision of original Win SDK 2. Enable non-client area DPI scaling when building with Qt < 5.9.0 Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- .../Core/framelesshelper_windows.h | 141 +++++++++++------- include/FramelessHelper/Core/utils.h | 1 + src/core/framelesshelper_win.cpp | 11 ++ src/core/utils_win.cpp | 101 +++++++++++-- 4 files changed, 190 insertions(+), 64 deletions(-) diff --git a/include/FramelessHelper/Core/framelesshelper_windows.h b/include/FramelessHelper/Core/framelesshelper_windows.h index e4ef951..28d8701 100644 --- a/include/FramelessHelper/Core/framelesshelper_windows.h +++ b/include/FramelessHelper/Core/framelesshelper_windows.h @@ -145,11 +145,33 @@ #ifndef _DPI_AWARENESS_CONTEXTS_ # define _DPI_AWARENESS_CONTEXTS_ - DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); + DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); + using DPI_AWARENESS = enum DPI_AWARENESS + { + DPI_AWARENESS_INVALID = -1, + DPI_AWARENESS_UNAWARE = 0, + DPI_AWARENESS_SYSTEM_AWARE = 1, + DPI_AWARENESS_PER_MONITOR_AWARE = 2 + }; +#endif + +#ifndef DPI_AWARENESS_CONTEXT_UNAWARE # define DPI_AWARENESS_CONTEXT_UNAWARE (reinterpret_cast(-1)) +#endif + +#ifndef DPI_AWARENESS_CONTEXT_SYSTEM_AWARE # define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE (reinterpret_cast(-2)) +#endif + +#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE # define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (reinterpret_cast(-3)) +#endif + +#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 # define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (reinterpret_cast(-4)) +#endif + +#ifndef DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED # define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED (reinterpret_cast(-5)) #endif @@ -193,8 +215,8 @@ # define HKEY_PERFORMANCE_NLSTEXT (reinterpret_cast(static_cast(static_cast(0x80000060)))) #endif -#ifndef STATUS_SUCCESS -# define STATUS_SUCCESS (static_cast(0x00000000L)) +#ifndef _STATUS_SUCCESS +# define _STATUS_SUCCESS (static_cast<_NTSTATUS>(0x00000000L)) #endif #ifndef WTNCA_NODRAWCAPTION @@ -229,55 +251,62 @@ # define EXTERN_C_END } #endif -using NTSTATUS = LONG; +using _NTSTATUS = LONG; -#ifndef WINMMAPI -using MMRESULT = UINT; -using TIMECAPS = struct TIMECAPS +using _MMRESULT = UINT; +using _TIMECAPS = struct _TIMECAPS { UINT wPeriodMin; // minimum period supported UINT wPeriodMax; // maximum period supported }; -using PTIMECAPS = TIMECAPS *; -using NPTIMECAPS = TIMECAPS NEAR *; -using LPTIMECAPS = TIMECAPS FAR *; -#endif +using _PTIMECAPS = _TIMECAPS *; -using PROCESS_DPI_AWARENESS = enum PROCESS_DPI_AWARENESS +using _PROCESS_DPI_AWARENESS = enum _PROCESS_DPI_AWARENESS { - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2, - PROCESS_PER_MONITOR_DPI_AWARE_V2 = 3 + _PROCESS_DPI_UNAWARE = 0, + _PROCESS_SYSTEM_DPI_AWARE = 1, + _PROCESS_PER_MONITOR_DPI_AWARE = 2, + _PROCESS_PER_MONITOR_DPI_AWARE_V2 = 3, + _PROCESS_DPI_UNAWARE_GDISCALED = 4 }; -using MONITOR_DPI_TYPE = enum MONITOR_DPI_TYPE +using _MONITOR_DPI_TYPE = enum _MONITOR_DPI_TYPE { - MDT_EFFECTIVE_DPI = 0, - MDT_ANGULAR_DPI = 1, - MDT_RAW_DPI = 2, - MDT_DEFAULT = MDT_EFFECTIVE_DPI + _MDT_EFFECTIVE_DPI = 0, + _MDT_ANGULAR_DPI = 1, + _MDT_RAW_DPI = 2, + _MDT_DEFAULT = _MDT_EFFECTIVE_DPI }; -using DEVICE_SCALE_FACTOR = enum DEVICE_SCALE_FACTOR +using _DEVICE_SCALE_FACTOR = enum _DEVICE_SCALE_FACTOR { - DEVICE_SCALE_FACTOR_INVALID = 0, - SCALE_100_PERCENT = 100, - SCALE_120_PERCENT = 120, - SCALE_125_PERCENT = 125, - SCALE_140_PERCENT = 140, - SCALE_150_PERCENT = 150, - SCALE_160_PERCENT = 160, - SCALE_175_PERCENT = 175, - SCALE_180_PERCENT = 180, - SCALE_200_PERCENT = 200, - SCALE_225_PERCENT = 225, - SCALE_250_PERCENT = 250, - SCALE_300_PERCENT = 300, - SCALE_350_PERCENT = 350, - SCALE_400_PERCENT = 400, - SCALE_450_PERCENT = 450, - SCALE_500_PERCENT = 500 + _DEVICE_SCALE_FACTOR_INVALID = 0, + _SCALE_100_PERCENT = 100, + _SCALE_120_PERCENT = 120, + _SCALE_125_PERCENT = 125, + _SCALE_140_PERCENT = 140, + _SCALE_150_PERCENT = 150, + _SCALE_160_PERCENT = 160, + _SCALE_175_PERCENT = 175, + _SCALE_180_PERCENT = 180, + _SCALE_200_PERCENT = 200, + _SCALE_225_PERCENT = 225, + _SCALE_250_PERCENT = 250, + _SCALE_300_PERCENT = 300, + _SCALE_350_PERCENT = 350, + _SCALE_400_PERCENT = 400, + _SCALE_450_PERCENT = 450, + _SCALE_500_PERCENT = 500 +}; + +using _DPI_AWARENESS = enum _DPI_AWARENESS +{ + _DPI_AWARENESS_INVALID = -1, + _DPI_AWARENESS_UNAWARE = 0, + _DPI_AWARENESS_SYSTEM_AWARE = 1, + _DPI_AWARENESS_PER_MONITOR_AWARE = 2, + _DPI_AWARENESS_PER_MONITOR_AWARE_V2 = 3, + _DPI_AWARENESS_UNAWARE_GDISCALED = 4 }; using _DWMWINDOWATTRIBUTE = enum _DWMWINDOWATTRIBUTE @@ -362,8 +391,6 @@ using ACCENT_POLICY = struct ACCENT_POLICY DWORD AnimationId; }; using PACCENT_POLICY = ACCENT_POLICY *; -using NPACCENT_POLICY = ACCENT_POLICY NEAR *; -using LPACCENT_POLICY = ACCENT_POLICY FAR *; using WINDOWCOMPOSITIONATTRIBDATA = struct WINDOWCOMPOSITIONATTRIBDATA { @@ -372,8 +399,6 @@ using WINDOWCOMPOSITIONATTRIBDATA = struct WINDOWCOMPOSITIONATTRIBDATA DWORD cbData; }; using PWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA *; -using NPWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA NEAR *; -using LPWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA FAR *; using _WINDOWTHEMEATTRIBUTETYPE = enum _WINDOWTHEMEATTRIBUTETYPE { @@ -420,31 +445,31 @@ using IsDarkModeAllowedForAppPtr = BOOL(WINAPI *)(VOID); // Ordinal 139 EXTERN_C_START -DECLSPEC_IMPORT MMRESULT WINAPI +DECLSPEC_IMPORT _MMRESULT WINAPI timeGetDevCaps( - _Out_writes_bytes_(cbtc) LPTIMECAPS ptc, + _Out_writes_bytes_(cbtc) _PTIMECAPS ptc, _In_ UINT cbtc ); -DECLSPEC_IMPORT MMRESULT WINAPI +DECLSPEC_IMPORT _MMRESULT WINAPI timeBeginPeriod( _In_ UINT uPeriod ); -DECLSPEC_IMPORT MMRESULT WINAPI +DECLSPEC_IMPORT _MMRESULT WINAPI timeEndPeriod( _In_ UINT uPeriod ); DECLSPEC_IMPORT HRESULT WINAPI SetProcessDpiAwareness( - _In_ PROCESS_DPI_AWARENESS value + _In_ _PROCESS_DPI_AWARENESS value ); DECLSPEC_IMPORT HRESULT WINAPI GetDpiForMonitor( _In_ HMONITOR hMonitor, - _In_ MONITOR_DPI_TYPE dpiType, + _In_ _MONITOR_DPI_TYPE dpiType, _Out_ UINT *dpiX, _Out_ UINT *dpiY ); @@ -483,7 +508,22 @@ SetProcessDPIAware( DECLSPEC_IMPORT HRESULT WINAPI GetScaleFactorForMonitor( _In_ HMONITOR hMon, - _Out_ DEVICE_SCALE_FACTOR *pScale + _Out_ _DEVICE_SCALE_FACTOR *pScale +); + +DECLSPEC_IMPORT BOOL WINAPI +EnableNonClientDpiScaling( + _In_ HWND hWnd +); + +DECLSPEC_IMPORT DPI_AWARENESS_CONTEXT WINAPI +GetWindowDpiAwarenessContext( + _In_ HWND hWnd +); + +DECLSPEC_IMPORT DPI_AWARENESS WINAPI +GetAwarenessFromDpiAwarenessContext( + _In_ DPI_AWARENESS_CONTEXT value ); EXTERN_C_END @@ -497,3 +537,4 @@ EXTERN_C_END [[maybe_unused]] inline constexpr const wchar_t kSystemDarkThemeResourceName[] = L"DarkMode_Explorer"; [[maybe_unused]] inline constexpr const wchar_t kSystemLightThemeResourceName[] = L"Explorer"; [[maybe_unused]] inline constexpr const wchar_t kDesktopRegistryKey[] = LR"(Control Panel\Desktop)"; +[[maybe_unused]] inline constexpr const wchar_t kDarkModePropertyName[] = L"UseImmersiveDarkModeColors"; diff --git a/include/FramelessHelper/Core/utils.h b/include/FramelessHelper/Core/utils.h index 15edcb2..b6d6315 100644 --- a/include/FramelessHelper/Core/utils.h +++ b/include/FramelessHelper/Core/utils.h @@ -115,6 +115,7 @@ FRAMELESSHELPER_CORE_API void hideOriginalTitleBarElements (const WId windowId, const bool disable = true); FRAMELESSHELPER_CORE_API void setQtDarkModeAwareEnabled(const bool enable); FRAMELESSHELPER_CORE_API void refreshWin32ThemeResources(const WId windowId, const bool dark); +FRAMELESSHELPER_CORE_API void enableNonClientAreaDpiScalingForWindow(const WId windowId); #endif // Q_OS_WINDOWS #ifdef Q_OS_LINUX diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index fded546..c633fcd 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -615,6 +615,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me const WPARAM wParam = msg->wParam; const LPARAM lParam = msg->lParam; switch (uMsg) { +#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) + case WM_NCCREATE: { + // Enable automatic DPI scaling for the non-client area of the window, + // such as the caption bar, the scrollbars, and the menu bar. We need + // to do this explicitly and manually here (only inside WM_NCCREATE). + // If we are using the PMv2 DPI awareness level, the non-client area + // of the window will be scaled by the OS automatically, so there will + // be no need to do this in that case. + Utils::enableNonClientAreaDpiScalingForWindow(windowId); + } break; +#endif case WM_NCCALCSIZE: { // Windows是根据这个消息的返回值来设置窗口的客户区(窗口中真正显示的内容) // 和非客户区(标题栏、窗口边框、菜单栏和状态栏等Windows系统自行提供的部分 diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 1d90f8d..d8716f8 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -395,6 +395,11 @@ FRAMELESSHELPER_STRING_CONSTANT(AllowDarkModeForApp) FRAMELESSHELPER_STRING_CONSTANT(AllowDarkModeForWindow) FRAMELESSHELPER_STRING_CONSTANT(FlushMenuThemes) FRAMELESSHELPER_STRING_CONSTANT(RefreshImmersiveColorPolicyState) +FRAMELESSHELPER_STRING_CONSTANT(SetPropW) +FRAMELESSHELPER_STRING_CONSTANT(GetIsImmersiveColorUsingHighContrast) +FRAMELESSHELPER_STRING_CONSTANT(EnableNonClientDpiScaling) +FRAMELESSHELPER_STRING_CONSTANT(GetWindowDpiAwarenessContext) +FRAMELESSHELPER_STRING_CONSTANT(GetAwarenessFromDpiAwarenessContext) struct Win32UtilsHelperData { @@ -461,13 +466,13 @@ struct SYSTEM_METRIC { static const std::optional currentOsVer = []() -> std::optional { if (API_NT_AVAILABLE(RtlGetVersion)) { - using RtlGetVersionPtr = NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW); + using RtlGetVersionPtr = _NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW); const auto pRtlGetVersion = reinterpret_cast(SysApiLoader::instance()->get(kRtlGetVersion)); RTL_OSVERSIONINFOEXW osvi; SecureZeroMemory(&osvi, sizeof(osvi)); osvi.dwOSVersionInfoSize = sizeof(osvi); - if (pRtlGetVersion(reinterpret_cast(&osvi)) == STATUS_SUCCESS) { + if (pRtlGetVersion(reinterpret_cast(&osvi)) == _STATUS_SUCCESS) { return VersionNumber{int(osvi.dwMajorVersion), int(osvi.dwMinorVersion), int(osvi.dwBuildNumber)}; } } @@ -1006,7 +1011,7 @@ void Utils::syncWmPaintWithDwm() WARNING << getSystemErrorMessage(kQueryPerformanceFrequency); return; } - TIMECAPS tc = {}; + _TIMECAPS tc = {}; if (API_CALL_FUNCTION(timeGetDevCaps, &tc, sizeof(tc)) != MMSYSERR_NOERROR) { WARNING << "timeGetDevCaps() failed."; return; @@ -1077,7 +1082,7 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) // GetDpiForMonitor() is only available on Windows 8 and onwards. if (API_SHCORE_AVAILABLE(GetDpiForMonitor)) { UINT dpiX = 0, dpiY = 0; - const HRESULT hr = API_CALL_FUNCTION(GetDpiForMonitor, hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + const HRESULT hr = API_CALL_FUNCTION(GetDpiForMonitor, hMonitor, _MDT_EFFECTIVE_DPI, &dpiX, &dpiY); if (SUCCEEDED(hr) && (dpiX > 0) && (dpiY > 0)) { return (horizontal ? dpiX : dpiY); } else { @@ -1086,9 +1091,9 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal) } // GetScaleFactorForMonitor() is only available on Windows 8 and onwards. if (API_SHCORE_AVAILABLE(GetScaleFactorForMonitor)) { - DEVICE_SCALE_FACTOR factor = DEVICE_SCALE_FACTOR_INVALID; + _DEVICE_SCALE_FACTOR factor = _DEVICE_SCALE_FACTOR_INVALID; const HRESULT hr = API_CALL_FUNCTION(GetScaleFactorForMonitor, hMonitor, &factor); - if (SUCCEEDED(hr) && (factor != DEVICE_SCALE_FACTOR_INVALID)) { + if (SUCCEEDED(hr) && (factor != _DEVICE_SCALE_FACTOR_INVALID)) { return quint32(qRound(qreal(USER_DEFAULT_SCREEN_DPI) * qreal(factor) / qreal(100))); } else { WARNING << __getSystemErrorMessage(kGetScaleFactorForMonitor, hr); @@ -1216,6 +1221,24 @@ quint32 Utils::getWindowDpi(const WId windowId, const bool horizontal) WARNING << getSystemErrorMessage(kGetDpiForSystem); } } + if (const HDC hdc = GetDC(hwnd)) { + bool valid = false; + const int dpiX = GetDeviceCaps(hdc, LOGPIXELSX); + const int dpiY = GetDeviceCaps(hdc, LOGPIXELSY); + if ((dpiX > 0) && (dpiY > 0)) { + valid = true; + } else { + WARNING << getSystemErrorMessage(kGetDeviceCaps); + } + if (ReleaseDC(hwnd, hdc) == 0) { + WARNING << getSystemErrorMessage(kReleaseDC); + } + if (valid) { + return (horizontal ? dpiX : dpiY); + } + } else { + WARNING << getSystemErrorMessage(kGetDC); + } return getPrimaryScreenDpi(horizontal); } @@ -1563,7 +1586,7 @@ void Utils::tryToEnableHighestDpiAwarenessLevel() } } if (API_SHCORE_AVAILABLE(SetProcessDpiAwareness)) { - const auto SetProcessDpiAwareness2 = [](const PROCESS_DPI_AWARENESS pda) -> bool { + const auto SetProcessDpiAwareness2 = [](const _PROCESS_DPI_AWARENESS pda) -> bool { const HRESULT hr = API_CALL_FUNCTION(SetProcessDpiAwareness, pda); if (SUCCEEDED(hr)) { return true; @@ -1579,13 +1602,16 @@ void Utils::tryToEnableHighestDpiAwarenessLevel() WARNING << __getSystemErrorMessage(kSetProcessDpiAwareness, hr); return false; }; - if (SetProcessDpiAwareness2(PROCESS_PER_MONITOR_DPI_AWARE_V2)) { + if (SetProcessDpiAwareness2(_PROCESS_PER_MONITOR_DPI_AWARE_V2)) { return; } - if (SetProcessDpiAwareness2(PROCESS_PER_MONITOR_DPI_AWARE)) { + if (SetProcessDpiAwareness2(_PROCESS_PER_MONITOR_DPI_AWARE)) { return; } - if (SetProcessDpiAwareness2(PROCESS_SYSTEM_DPI_AWARE)) { + if (SetProcessDpiAwareness2(_PROCESS_SYSTEM_DPI_AWARE)) { + return; + } + if (SetProcessDpiAwareness2(_PROCESS_DPI_UNAWARE_GDISCALED)) { return; } } @@ -2038,8 +2064,15 @@ void Utils::refreshWin32ThemeResources(const WId windowId, const bool dark) if (AllowDarkModeForWindow(hWnd, darkFlag) == FALSE) { WARNING << getSystemErrorMessage(kAllowDarkModeForWindow); } - if (SetWindowCompositionAttribute(hWnd, &wcad) == FALSE) { - WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute); + if (WindowsVersionHelper::isWin1019H1OrGreater()) { + if (SetWindowCompositionAttribute(hWnd, &wcad) == FALSE) { + WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute); + } + } else { + if (SetPropW(hWnd, kDarkModePropertyName, + reinterpret_cast(static_cast(darkFlag))) == FALSE) { + WARNING << getSystemErrorMessage(kSetPropW); + } } const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hWnd, borderFlag, &darkFlag, sizeof(darkFlag)); if (FAILED(hr)) { @@ -2055,12 +2088,22 @@ void Utils::refreshWin32ThemeResources(const WId windowId, const bool dark) if (GetLastError() != ERROR_SUCCESS) { WARNING << getSystemErrorMessage(kRefreshImmersiveColorPolicyState); } + if (GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH) == FALSE) { + WARNING << getSystemErrorMessage(kGetIsImmersiveColorUsingHighContrast); + } } else { if (AllowDarkModeForWindow(hWnd, darkFlag) == FALSE) { WARNING << getSystemErrorMessage(kAllowDarkModeForWindow); } - if (SetWindowCompositionAttribute(hWnd, &wcad) == FALSE) { - WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute); + if (WindowsVersionHelper::isWin1019H1OrGreater()) { + if (SetWindowCompositionAttribute(hWnd, &wcad) == FALSE) { + WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute); + } + } else { + if (SetPropW(hWnd, kDarkModePropertyName, + reinterpret_cast(static_cast(darkFlag))) == FALSE) { + WARNING << getSystemErrorMessage(kSetPropW); + } } const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hWnd, borderFlag, &darkFlag, sizeof(darkFlag)); if (FAILED(hr)) { @@ -2076,6 +2119,9 @@ void Utils::refreshWin32ThemeResources(const WId windowId, const bool dark) if (GetLastError() != ERROR_SUCCESS) { WARNING << getSystemErrorMessage(kRefreshImmersiveColorPolicyState); } + if (GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH) == FALSE) { + WARNING << getSystemErrorMessage(kGetIsImmersiveColorUsingHighContrast); + } if (WindowsVersionHelper::isWin1019H1OrGreater()) { if (SetPreferredAppMode(appMode) == PAM_MAX) { WARNING << getSystemErrorMessage(kSetPreferredAppMode); @@ -2088,4 +2134,31 @@ void Utils::refreshWin32ThemeResources(const WId windowId, const bool dark) } } +void Utils::enableNonClientAreaDpiScalingForWindow(const WId windowId) +{ + Q_ASSERT(windowId); + if (!windowId) { + return; + } + if (!(API_USER_AVAILABLE(EnableNonClientDpiScaling) + && API_USER_AVAILABLE(GetWindowDpiAwarenessContext) + && API_USER_AVAILABLE(GetAwarenessFromDpiAwarenessContext))) { + return; + } + const auto hwnd = reinterpret_cast(windowId); + const DPI_AWARENESS_CONTEXT context = API_CALL_FUNCTION(GetWindowDpiAwarenessContext, hwnd); + if (!context) { + WARNING << getSystemErrorMessage(kGetWindowDpiAwarenessContext); + return; + } + const auto awareness = static_cast<_DPI_AWARENESS>( + API_CALL_FUNCTION(GetAwarenessFromDpiAwarenessContext, context)); + if (awareness == _DPI_AWARENESS_PER_MONITOR_AWARE_V2) { + return; + } + if (API_CALL_FUNCTION(EnableNonClientDpiScaling, hwnd) == FALSE) { + WARNING << getSystemErrorMessage(kEnableNonClientDpiScaling); + } +} + FRAMELESSHELPER_END_NAMESPACE