From a5a5942d80198a441715490a05b195e05d547021 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Sun, 5 Sep 2021 09:20:19 +0800 Subject: [PATCH] Win32: Add some useful functions back 1. Also rename some leftovers to more appropriate names 2. Be more verbose to help debugging TODO: improve widget example, make use of the these functions Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- framelesshelper_global.h | 20 +++ framelesshelper_win32.cpp | 34 +++-- framelesswindowsmanager.cpp | 4 +- utilities.h | 14 +- utilities_linux.cpp | 56 ++++++++ utilities_win32.cpp | 274 ++++++++++++++++++++++++++++++++---- 6 files changed, 349 insertions(+), 53 deletions(-) diff --git a/framelesshelper_global.h b/framelesshelper_global.h index 59a4fde..aa5f7c1 100644 --- a/framelesshelper_global.h +++ b/framelesshelper_global.h @@ -25,6 +25,7 @@ #pragma once #include +#include #ifndef FRAMELESSHELPER_API #ifdef FRAMELESSHELPER_STATIC @@ -85,6 +86,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE +Q_NAMESPACE_EXPORT(FRAMELESSHELPER_API) + namespace Constants { @@ -100,4 +103,21 @@ namespace Constants } +enum class SystemMetric : int +{ + ResizeBorderThickness = 0, + CaptionHeight, + TitleBarHeight +}; +Q_ENUM_NS(SystemMetric) + +enum class ColorizationArea : int +{ + None = 0, + StartMenu_TaskBar_ActionCenter, + TitleBar_WindowBorder, + All +}; +Q_ENUM_NS(ColorizationArea) + FRAMELESSHELPER_END_NAMESPACE diff --git a/framelesshelper_win32.cpp b/framelesshelper_win32.cpp index 02ca8ac..b00b60f 100644 --- a/framelesshelper_win32.cpp +++ b/framelesshelper_win32.cpp @@ -320,12 +320,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // then the window is clipped to the monitor so that the resize handle // do not appear because you don't need them (because you can't resize // a window when it's maximized unless you restore it). - const int rbt = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true); - clientRect->top += rbt; + const int resizeBorderThickness = Utilities::getSystemMetric(window, SystemMetric::ResizeBorderThickness, true); + clientRect->top += resizeBorderThickness; if (!shouldHaveWindowFrame()) { - clientRect->bottom -= rbt; - clientRect->left += rbt; - clientRect->right -= rbt; + clientRect->bottom -= resizeBorderThickness; + clientRect->left += resizeBorderThickness; + clientRect->right -= resizeBorderThickness; } nonClientAreaExists = true; } @@ -352,11 +352,13 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me monitorInfo.cbSize = sizeof(monitorInfo); const HMONITOR monitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST); if (!monitor) { - qWarning() << "Failed to retrieve the screen that contains the current window."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("MonitorFromWindow"), hr); break; } if (GetMonitorInfoW(monitor, &monitorInfo) == FALSE) { - qWarning() << "Failed to retrieve the screen information."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("GetMonitorInfoW"), hr); break; } // This helper can be used to determine if there's a @@ -386,12 +388,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me if (_abd.hWnd) { const HMONITOR windowMonitor = MonitorFromWindow(msg->hwnd, MONITOR_DEFAULTTONEAREST); if (!windowMonitor) { - qWarning() << "Failed to retrieve the screen that contains the current window."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("MonitorFromWindow"), hr); break; } const HMONITOR taskbarMonitor = MonitorFromWindow(_abd.hWnd, MONITOR_DEFAULTTOPRIMARY); if (!taskbarMonitor) { - qWarning() << "Failed to retrieve the screen that contains the task bar."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("MonitorFromWindow"), hr); break; } if (taskbarMonitor == windowMonitor) { @@ -580,13 +584,15 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me POINT winLocalMouse = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)}; if (ScreenToClient(msg->hwnd, &winLocalMouse) == FALSE) { - qWarning() << "Failed to translate global screen coordinate to local window coordinate."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("ScreenToClient"), hr); break; } const QPointF localMouse = {static_cast(winLocalMouse.x), static_cast(winLocalMouse.y)}; RECT clientRect = {0, 0, 0, 0}; if (GetClientRect(msg->hwnd, &clientRect) == FALSE) { - qWarning() << "Failed to retrieve the client rect of the current window."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("GetClientRect"), hr); break; } const LONG windowWidth = clientRect.right; @@ -690,14 +696,16 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // Prevent Windows from drawing the default title bar by temporarily // toggling the WS_VISIBLE style. if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle & ~WS_VISIBLE) == 0) { - qWarning() << "SetWindowLongPtrW() failed."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"), hr); break; } const auto winId = reinterpret_cast(msg->hwnd); Utilities::triggerFrameChange(winId); const LRESULT ret = DefWindowProcW(msg->hwnd, msg->message, msg->wParam, msg->lParam); if (SetWindowLongPtrW(msg->hwnd, GWL_STYLE, oldStyle) == 0) { - qWarning() << "SetWindowLongPtrW() failed."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << Utilities::getSystemErrorMessage(QStringLiteral("SetWindowLongPtrW"), hr); break; } Utilities::triggerFrameChange(winId); diff --git a/framelesswindowsmanager.cpp b/framelesswindowsmanager.cpp index 9a3b356..6eaa095 100644 --- a/framelesswindowsmanager.cpp +++ b/framelesswindowsmanager.cpp @@ -122,11 +122,11 @@ int FramelessWindowsManager::getTitleBarHeight(const QWindow *window) { Q_ASSERT(window); if (!window) { - return 23; + return 31; } #ifdef FRAMELESSHELPER_USE_UNIX_VERSION const int value = window->property(Constants::kTitleBarHeightFlag).toInt(); - return value <= 0 ? 23 : value; + return value <= 0 ? 31 : value; #else return Utilities::getSystemMetric(window, SystemMetric::TitleBarHeight, false); #endif diff --git a/utilities.h b/utilities.h index dab5995..e2d5dc0 100644 --- a/utilities.h +++ b/utilities.h @@ -29,13 +29,6 @@ FRAMELESSHELPER_BEGIN_NAMESPACE -enum class SystemMetric : int -{ - ResizeBorderThickness = 0, - CaptionHeight, - TitleBarHeight -}; - namespace Utilities { @@ -54,6 +47,13 @@ namespace Utilities FRAMELESSHELPER_API void triggerFrameChange(const WId winId); FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset); FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable); +[[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function, const HRESULT hr); +[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor(); +[[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const QWindow *window); +[[nodiscard]] FRAMELESSHELPER_API bool shouldAppsUseDarkMode(); +[[nodiscard]] FRAMELESSHELPER_API bool isHighContrastModeEnabled(); +[[nodiscard]] FRAMELESSHELPER_API ColorizationArea getColorizationArea(); +[[nodiscard]] FRAMELESSHELPER_API bool isWindowDarkFrameBorderEnabled(const WId winId); #endif } diff --git a/utilities_linux.cpp b/utilities_linux.cpp index 53fb5a7..e8e1023 100644 --- a/utilities_linux.cpp +++ b/utilities_linux.cpp @@ -23,3 +23,59 @@ */ #include "utilities.h" + +static constexpr int kDefaultResizeBorderThickness = 8; +static constexpr int kDefaultCaptionHeight = 23; + +int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue) +{ + Q_ASSERT(window); + if (!window) { + return 0; + } + const qreal devicePixelRatio = window->devicePixelRatio(); + const qreal scaleFactor = (dpiScale ? devicePixelRatio : 1.0); + switch (metric) { + case SystemMetric::ResizeBorderThickness: { + const int resizeBorderThickness = window->property(Constants::kResizeBorderThicknessFlag).toInt(); + if ((resizeBorderThickness > 0) && !forceSystemValue) { + return qRound(static_cast(resizeBorderThickness) * scaleFactor); + } else { + // ### TODO: Retrieve system value through official API + if (dpiScale) { + return qRound(static_cast(kDefaultResizeBorderThickness) * devicePixelRatio); + } else { + return kDefaultResizeBorderThickness; + } + } + } + case SystemMetric::CaptionHeight: { + const int captionHeight = window->property(Constants::kCaptionHeightFlag).toInt(); + if ((captionHeight > 0) && !forceSystemValue) { + return qRound(static_cast(captionHeight) * scaleFactor); + } else { + // ### TODO: Retrieve system value through official API + if (dpiScale) { + return qRound(static_cast(kDefaultCaptionHeight) * devicePixelRatio); + } else { + return kDefaultCaptionHeight; + } + } + } + case SystemMetric::TitleBarHeight: { + const int titleBarHeight = window->property(Constants::kTitleBarHeightFlag).toInt(); + if ((titleBarHeight > 0) && !forceSystemValue) { + return qRound(static_cast(titleBarHeight) * scaleFactor); + } else { + const int captionHeight = getSystemMetric(window,SystemMetric::CaptionHeight, + dpiScale, forceSystemValue); + const int resizeBorderThickness = getSystemMetric(window, SystemMetric::ResizeBorderThickness, + dpiScale, forceSystemValue); + return (((window->windowState() == Qt::WindowMaximized) + || (window->windowState() == Qt::WindowFullScreen)) + ? captionHeight : (captionHeight + resizeBorderThickness)); + } + } + } + return 0; +} diff --git a/utilities_win32.cpp b/utilities_win32.cpp index 7c461de..ea1f0a2 100644 --- a/utilities_win32.cpp +++ b/utilities_win32.cpp @@ -49,26 +49,87 @@ Q_DECLARE_METATYPE(QMargins) FRAMELESSHELPER_BEGIN_NAMESPACE -static constexpr char kDwmRegistryKey[] = R"(Software\Microsoft\Windows\DWM)"; +static constexpr char kDwmRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)"; +static constexpr char kPersonalizeRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"; static constexpr int kDefaultResizeBorderThicknessClassic = 4; static constexpr int kDefaultResizeBorderThicknessAero = 8; static constexpr int kDefaultCaptionHeight = 23; +enum : WORD +{ + _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, + _DWMWA_USE_IMMERSIVE_DARK_MODE = 20, + _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37 +}; + +[[nodiscard]] static inline bool isWin10RS1OrGreater() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) + static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)); +#else + static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10); +#endif + return result; +} + +[[nodiscard]] static inline bool isWin1019H1OrGreater() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) + static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 18362)); +#else + static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10); +#endif + return result; +} + +bool Utilities::isWin8OrGreater() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) + static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8); +#else + static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8); +#endif + return result; +} + +bool Utilities::isWin8Point1OrGreater() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) + static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8_1); +#else + static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8_1); +#endif + return result; +} + +bool Utilities::isWin10OrGreater() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) + static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10); +#else + static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10); +#endif + return result; +} + bool Utilities::isDwmCompositionAvailable() { - // DWM Composition is always enabled and can't be disabled since Windows 8. + // DWM composition is always enabled and can't be disabled since Windows 8. if (isWin8OrGreater()) { return true; } BOOL enabled = FALSE; - if (SUCCEEDED(DwmIsCompositionEnabled(&enabled))) { + const HRESULT hr = DwmIsCompositionEnabled(&enabled); + if (SUCCEEDED(hr)) { return (enabled != FALSE); + } else { + qWarning() << getSystemErrorMessage(QStringLiteral("DwmIsCompositionEnabled"), hr); + const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat); + bool ok = false; + const DWORD value = registry.value(QStringLiteral("Composition"), 0).toUInt(&ok); + return (ok && (value != 0)); } - const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat); - bool ok = false; - const int value = registry.value(QStringLiteral("Composition"), 0).toInt(&ok); - return (ok && (value != 0)); } int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, const bool dpiScale, const bool forceSystemValue) @@ -93,6 +154,8 @@ int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, return qRound(static_cast(result) / devicePixelRatio); } } else { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("GetSystemMetrics"), hr); // The padded border will disappear if DWM composition is disabled. const int defaultResizeBorderThickness = (isDwmCompositionAvailable() ? kDefaultResizeBorderThicknessAero : kDefaultResizeBorderThicknessClassic); if (dpiScale) { @@ -116,6 +179,8 @@ int Utilities::getSystemMetric(const QWindow *window, const SystemMetric metric, return qRound(static_cast(result) / devicePixelRatio); } } else { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("GetSystemMetrics"), hr); if (dpiScale) { return qRound(static_cast(kDefaultCaptionHeight) * devicePixelRatio); } else { @@ -151,7 +216,8 @@ void Utilities::triggerFrameChange(const WId winId) const auto hwnd = reinterpret_cast(winId); constexpr UINT flags = (SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); if (SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, flags) == FALSE) { - qWarning() << "SetWindowPos() failed."; + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SetWindowPos"), hr); } } @@ -168,8 +234,9 @@ void Utilities::updateFrameMargins(const WId winId, const bool reset) } const auto hwnd = reinterpret_cast(winId); const MARGINS margins = reset ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1}; - if (FAILED(DwmExtendFrameIntoClientArea(hwnd, &margins))) { - qWarning() << "DwmExtendFrameIntoClientArea() failed."; + const HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins); + if (FAILED(hr)) { + qWarning() << getSystemErrorMessage(QStringLiteral("DwmExtendFrameIntoClientArea"), hr); } } @@ -191,44 +258,189 @@ void Utilities::updateQtFrameMargins(QWindow *window, const bool enable) QPlatformWindow *platformWindow = window->handle(); if (platformWindow) { QGuiApplication::platformNativeInterface()->setWindowProperty(platformWindow, QStringLiteral("WindowsCustomMargins"), marginsVar); + } else { + qWarning() << "Failed to retrieve the platform window."; } #else auto *platformWindow = dynamic_cast( window->handle()); if (platformWindow) { platformWindow->setCustomMargins(margins); + } else { + qWarning() << "Failed to retrieve the platform window."; } #endif } -bool Utilities::isWin8OrGreater() +QString Utilities::getSystemErrorMessage(const QString &function, const HRESULT hr) { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) - static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8); -#else - static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8); -#endif - return result; + Q_ASSERT(!function.isEmpty()); + if (function.isEmpty()) { + return {}; + } + if (SUCCEEDED(hr)) { + return QStringLiteral("Operation succeeded."); + } + const DWORD dwError = HRESULT_CODE(hr); + LPWSTR buf = nullptr; + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, nullptr) == 0) { + return QStringLiteral("Failed to retrieve the error message from system."); + } + const QString message = QStringLiteral("%1 failed with error %2: %3.") + .arg(function, QString::number(dwError), QString::fromWCharArray(buf)); + LocalFree(buf); + return message; } -bool Utilities::isWin8Point1OrGreater() +QColor Utilities::getColorizationColor() { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) - static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8_1); -#else - static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS8_1); -#endif - return result; + COLORREF color = RGB(0, 0, 0); + BOOL opaque = FALSE; + const HRESULT hr = DwmGetColorizationColor(&color, &opaque); + if (FAILED(hr)) { + qWarning() << getSystemErrorMessage(QStringLiteral("DwmGetColorizationColor"), hr); + const QSettings registry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat); + bool ok = false; + color = registry.value(QStringLiteral("ColorizationColor"), 0).toUInt(&ok); + if (!ok || (color == 0)) { + color = RGB(128, 128, 128); // Dark gray + } + } + return QColor::fromRgba(color); } -bool Utilities::isWin10OrGreater() +int Utilities::getWindowVisibleFrameBorderThickness(const QWindow *window) { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) - static const bool result = (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10); -#else - static const bool result = (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS10); -#endif - return result; + Q_ASSERT(window); + if (!window) { + return 0; + } + if (!isWin10OrGreater()) { + return 0; + } + const auto hWnd = reinterpret_cast(window->winId()); + UINT value = 0; + const HRESULT hr = DwmGetWindowAttribute(hWnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value)); + if (SUCCEEDED(hr)) { + return value; + } else { + // We just eat this error because this enum value was introduced in a very + // late Windows 10 version, so querying it's value will always result in + // a "parameter error" (code: 87) on systems before that value was introduced. + } + const bool max = (window->windowState() == Qt::WindowMaximized); + const bool full = (window->windowState() == Qt::WindowFullScreen); + return ((max || full) ? 0 : qRound(1.0 * window->devicePixelRatio())); +} + +bool Utilities::shouldAppsUseDarkMode() +{ + if (!isWin10RS1OrGreater()) { + return false; + } + const auto resultFromRegistry = []() -> bool { + const QSettings registry(QString::fromUtf8(kPersonalizeRegistryKey), QSettings::NativeFormat); + bool ok = false; + const DWORD value = registry.value(QStringLiteral("AppsUseLightTheme"), 0).toUInt(&ok); + return (ok && (value == 0)); + }; + // Starting from Windows 10 19H1, ShouldAppsUseDarkMode() always return "TRUE" + // (actually, a random non-zero number at runtime), so we can't use it due to + // this unreliability. In this case, we just simply read the user's setting from + // the registry instead, it's not elegant but at least it works well. + if (isWin1019H1OrGreater()) { + return resultFromRegistry(); + } else { + static bool tried = false; + using sig = BOOL(WINAPI *)(); + static sig func = nullptr; + if (!func) { + if (tried) { + return resultFromRegistry(); + } else { + tried = true; + const HMODULE dll = LoadLibraryExW(L"UxTheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (!dll) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("LoadLibraryExW"), hr); + return resultFromRegistry(); + } + func = reinterpret_cast(GetProcAddress(dll, MAKEINTRESOURCEA(132))); + if (!func) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("GetProcAddress"), hr); + return resultFromRegistry(); + } + } + } + return (func() != FALSE); + } +} + +bool Utilities::isHighContrastModeEnabled() +{ + HIGHCONTRASTW hc; + SecureZeroMemory(&hc, sizeof(hc)); + hc.cbSize = sizeof(hc); + if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(hc), &hc, 0) == FALSE) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SystemParametersInfoW"), hr); + return false; + } + return (hc.dwFlags & HCF_HIGHCONTRASTON); +} + +ColorizationArea Utilities::getColorizationArea() +{ + if (!isWin10OrGreater()) { + return ColorizationArea::None; + } + const QString keyName = QStringLiteral("ColorPrevalence"); + const QSettings themeRegistry(QString::fromUtf8(kPersonalizeRegistryKey), QSettings::NativeFormat); + const DWORD themeValue = themeRegistry.value(keyName, 0).toUInt(); + const QSettings dwmRegistry(QString::fromUtf8(kDwmRegistryKey), QSettings::NativeFormat); + const DWORD dwmValue = dwmRegistry.value(keyName, 0).toUInt(); + const bool theme = (themeValue != 0); + const bool dwm = (dwmValue != 0); + if (theme && dwm) { + return ColorizationArea::All; + } else if (theme) { + return ColorizationArea::StartMenu_TaskBar_ActionCenter; + } else if (dwm) { + return ColorizationArea::TitleBar_WindowBorder; + } + return ColorizationArea::None; +} + +bool Utilities::isWindowDarkFrameBorderEnabled(const WId winId) +{ + Q_ASSERT(winId); + if (!winId) { + return false; + } + if (!isWin10RS1OrGreater()) { + return false; + } + const auto hWnd = reinterpret_cast(winId); + BOOL enabled = FALSE; + HRESULT hr = DwmGetWindowAttribute(hWnd, _DWMWA_USE_IMMERSIVE_DARK_MODE, &enabled, sizeof(enabled)); + if (SUCCEEDED(hr)) { + return (enabled != FALSE); + } else { + // We just eat this error because this enum value was introduced in a very + // late Windows 10 version, so querying it's value will always result in + // a "parameter error" (code: 87) on systems before that value was introduced. + } + hr = DwmGetWindowAttribute(hWnd, _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, &enabled, sizeof(enabled)); + if (SUCCEEDED(hr)) { + return (enabled != FALSE); + } else { + // We just eat this error because this enum value was introduced in a very + // late Windows 10 version, so querying it's value will always result in + // a "parameter error" (code: 87) on systems before that value was introduced. + } + return false; } FRAMELESSHELPER_END_NAMESPACE