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>
This commit is contained in:
Yuhang Zhao 2022-10-20 14:15:11 +08:00
parent fe6fb8ef5f
commit af6d3c7380
4 changed files with 190 additions and 64 deletions

View File

@ -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<DPI_AWARENESS_CONTEXT>(-1))
#endif
#ifndef DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
# define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE (reinterpret_cast<DPI_AWARENESS_CONTEXT>(-2))
#endif
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (reinterpret_cast<DPI_AWARENESS_CONTEXT>(-3))
#endif
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (reinterpret_cast<DPI_AWARENESS_CONTEXT>(-4))
#endif
#ifndef DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED
# define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED (reinterpret_cast<DPI_AWARENESS_CONTEXT>(-5))
#endif
@ -193,8 +215,8 @@
# define HKEY_PERFORMANCE_NLSTEXT (reinterpret_cast<HKEY>(static_cast<ULONG_PTR>(static_cast<LONG>(0x80000060))))
#endif
#ifndef STATUS_SUCCESS
# define STATUS_SUCCESS (static_cast<NTSTATUS>(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";

View File

@ -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

View File

@ -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系统自行提供的部分

View File

@ -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<VersionNumber> currentOsVer = []() -> std::optional<VersionNumber> {
if (API_NT_AVAILABLE(RtlGetVersion)) {
using RtlGetVersionPtr = NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
using RtlGetVersionPtr = _NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
const auto pRtlGetVersion =
reinterpret_cast<RtlGetVersionPtr>(SysApiLoader::instance()->get(kRtlGetVersion));
RTL_OSVERSIONINFOEXW osvi;
SecureZeroMemory(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
if (pRtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(&osvi)) == STATUS_SUCCESS) {
if (pRtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(&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<HANDLE>(static_cast<INT_PTR>(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<HANDLE>(static_cast<INT_PTR>(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<HWND>(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