win32: add support for dark theme menu

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-10-11 16:17:04 +08:00
parent fcf51d6d73
commit b9f5cf79c0
12 changed files with 419 additions and 105 deletions

View File

@ -134,7 +134,7 @@ void Dialog::setupUi()
// with making the window un-resizable: we still want the window be able to resize // with making the window un-resizable: we still want the window be able to resize
// programatically, but we also want the user not able to resize the window manually. // programatically, but we also want the user not able to resize the window manually.
// So apparently we can't use QWidget::setFixedWidth/Height/Size() here. // So apparently we can't use QWidget::setFixedWidth/Height/Size() here.
FramelessWidgetsHelperPrivate::get(helper)->setProperty(FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_DONT_OVERRIDE_CURSOR"), true); FramelessWidgetsHelperPrivate::get(helper)->setProperty(kDontOverrideCursorVar, true);
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){ connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
const QScopedPointer<QSettings> settings(appConfigFile()); const QScopedPointer<QSettings> settings(appConfigFile());
const QByteArray data = settings->value(kIniKeyPath).toByteArray(); const QByteArray data = settings->value(kIniKeyPath).toByteArray();

View File

@ -58,8 +58,8 @@
# define _WIN32_WINNT_WIN10 0x0A00 # define _WIN32_WINNT_WIN10 0x0A00
#endif #endif
#ifndef NTDDI_WIN10_CO #ifndef NTDDI_WIN10_NI
# define NTDDI_WIN10_CO 0x0A00000B # define NTDDI_WIN10_NI 0x0A00000C
#endif #endif
#ifndef WINVER #ifndef WINVER
@ -71,7 +71,7 @@
#endif #endif
#ifndef NTDDI_VERSION #ifndef NTDDI_VERSION
# define NTDDI_VERSION NTDDI_WIN10_CO # define NTDDI_VERSION NTDDI_WIN10_NI
#endif #endif
#include <windows.h> #include <windows.h>
@ -375,9 +375,6 @@ using PWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA *;
using NPWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA NEAR *; using NPWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA NEAR *;
using LPWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA FAR *; using LPWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA FAR *;
using GetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, PWINDOWCOMPOSITIONATTRIBDATA);
using SetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, PWINDOWCOMPOSITIONATTRIBDATA);
using _WINDOWTHEMEATTRIBUTETYPE = enum _WINDOWTHEMEATTRIBUTETYPE using _WINDOWTHEMEATTRIBUTETYPE = enum _WINDOWTHEMEATTRIBUTETYPE
{ {
_WTA_NONCLIENT = 1 _WTA_NONCLIENT = 1
@ -390,6 +387,37 @@ using WTA_OPTIONS2 = struct WTA_OPTIONS2
}; };
using PWTA_OPTIONS2 = WTA_OPTIONS2 *; using PWTA_OPTIONS2 = WTA_OPTIONS2 *;
using IMMERSIVE_HC_CACHE_MODE = enum IMMERSIVE_HC_CACHE_MODE
{
IHCM_USE_CACHED_VALUE = 0,
IHCM_REFRESH = 1
};
using PREFERRED_APP_MODE = enum PREFERRED_APP_MODE
{
PAM_DEFAULT = 0,
PAM_ALLOW_DARK = 1,
PAM_FORCE_DARK = 2,
PAM_FORCE_LIGHT = 3,
PAM_MAX = 4
};
using GetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, PWINDOWCOMPOSITIONATTRIBDATA);
using SetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, PWINDOWCOMPOSITIONATTRIBDATA);
// Win10 1809 (10.0.17763)
using ShouldAppsUseDarkModePtr = BOOL(WINAPI *)(VOID); // Ordinal 132
using AllowDarkModeForWindowPtr = BOOL(WINAPI *)(HWND, BOOL); // Ordinal 133
using AllowDarkModeForAppPtr = BOOL(WINAPI *)(BOOL); // Ordinal 135
using FlushMenuThemesPtr = VOID(WINAPI *)(VOID); // Ordinal 136
using RefreshImmersiveColorPolicyStatePtr = VOID(WINAPI *)(VOID); // Ordinal 104
using IsDarkModeAllowedForWindowPtr = BOOL(WINAPI *)(HWND); // Ordinal 137
using GetIsImmersiveColorUsingHighContrastPtr = BOOL(WINAPI *)(IMMERSIVE_HC_CACHE_MODE); // Ordinal 106
using OpenNcThemeDataPtr = HTHEME(WINAPI *)(HWND, LPCWSTR); // Ordinal 49
// Win10 1903 (10.0.18362)
using ShouldSystemUseDarkModePtr = BOOL(WINAPI *)(VOID); // Ordinal 138
using SetPreferredAppModePtr = PREFERRED_APP_MODE(WINAPI *)(PREFERRED_APP_MODE); // Ordinal 135
using IsDarkModeAllowedForAppPtr = BOOL(WINAPI *)(VOID); // Ordinal 139
EXTERN_C_START EXTERN_C_START
DECLSPEC_IMPORT MMRESULT WINAPI DECLSPEC_IMPORT MMRESULT WINAPI

View File

@ -235,6 +235,11 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
[[maybe_unused]] inline Q_CONSTEXPR2 const QColor kDefaultSystemButtonBackgroundColor = {204, 204, 204}; // #CCCCCC [[maybe_unused]] inline Q_CONSTEXPR2 const QColor kDefaultSystemButtonBackgroundColor = {204, 204, 204}; // #CCCCCC
[[maybe_unused]] inline Q_CONSTEXPR2 const QColor kDefaultSystemCloseButtonBackgroundColor = {232, 17, 35}; // #E81123 [[maybe_unused]] inline Q_CONSTEXPR2 const QColor kDefaultSystemCloseButtonBackgroundColor = {232, 17, 35}; // #E81123
[[maybe_unused]] inline const QByteArray kDontOverrideCursorVar
= FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_DONT_OVERRIDE_CURSOR");
[[maybe_unused]] inline const QByteArray kDontToggleMaximizeVar
= FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_DONT_TOGGLE_MAXIMIZE");
enum class Option enum class Option
{ {
UseCrossPlatformQtImplementation = 0, UseCrossPlatformQtImplementation = 0,
@ -373,10 +378,10 @@ Q_ENUM_NS(RegistryRootKey)
enum class WindowEdge enum class WindowEdge
{ {
Unspecified = 0x00000000, Unspecified = 0x00000000,
Left = 0x00000002, Left = 0x00000001,
Top = 0x00000004, Top = 0x00000002,
Right = 0x00000008, Right = 0x00000004,
Bottom = 0x00000010 Bottom = 0x00000008
}; };
Q_ENUM_NS(WindowEdge) Q_ENUM_NS(WindowEdge)
Q_DECLARE_FLAGS(WindowEdges, WindowEdge) Q_DECLARE_FLAGS(WindowEdges, WindowEdge)

View File

@ -41,6 +41,7 @@ public:
Q_NODISCARD static SysApiLoader *instance(); Q_NODISCARD static SysApiLoader *instance();
Q_NODISCARD static QFunctionPointer resolve(const QString &library, const char *function);
Q_NODISCARD static QFunctionPointer resolve(const QString &library, const QByteArray &function); Q_NODISCARD static QFunctionPointer resolve(const QString &library, const QByteArray &function);
Q_NODISCARD static QFunctionPointer resolve(const QString &library, const QString &function); Q_NODISCARD static QFunctionPointer resolve(const QString &library, const QString &function);

View File

@ -96,7 +96,6 @@ FRAMELESSHELPER_CORE_API void showSystemMenu(
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getTitleBarHeight(const WId windowId, const bool scaled); [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getTitleBarHeight(const WId windowId, const bool scaled);
[[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const WId windowId, [[nodiscard]] FRAMELESSHELPER_CORE_API quint32 getFrameBorderThickness(const WId windowId,
const bool scaled); const bool scaled);
FRAMELESSHELPER_CORE_API void updateWindowFrameBorderColor(const WId windowId, const bool dark);
FRAMELESSHELPER_CORE_API void maybeFixupQtInternals(const WId windowId); FRAMELESSHELPER_CORE_API void maybeFixupQtInternals(const WId windowId);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowFrameBorderVisible();
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized(); [[nodiscard]] FRAMELESSHELPER_CORE_API bool isFrameBorderColorized();
@ -115,6 +114,7 @@ FRAMELESSHELPER_CORE_API void forceSquareCornersForWindow(const WId windowId, co
FRAMELESSHELPER_CORE_API void disableOriginalTitleBarFunctionalities FRAMELESSHELPER_CORE_API void disableOriginalTitleBarFunctionalities
(const WId windowId, const bool disable = true); (const WId windowId, const bool disable = true);
FRAMELESSHELPER_CORE_API void setQtDarkModeAwareEnabled(const bool enable); FRAMELESSHELPER_CORE_API void setQtDarkModeAwareEnabled(const bool enable);
FRAMELESSHELPER_CORE_API void refreshWin32ThemeResources(const WId windowId, const bool dark);
#endif // Q_OS_WINDOWS #endif // Q_OS_WINDOWS
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX

View File

@ -40,10 +40,10 @@ function(setup_compile_params arg_target)
) )
if(WIN32) # Needed by both MSVC and MinGW if(WIN32) # Needed by both MSVC and MinGW
set(_WIN32_WINNT_WIN10 0x0A00) set(_WIN32_WINNT_WIN10 0x0A00)
set(NTDDI_WIN10_CO 0x0A00000B) set(NTDDI_WIN10_NI 0x0A00000C)
target_compile_definitions(${arg_target} PRIVATE target_compile_definitions(${arg_target} PRIVATE
WINVER=${_WIN32_WINNT_WIN10} _WIN32_WINNT=${_WIN32_WINNT_WIN10} WINVER=${_WIN32_WINNT_WIN10} _WIN32_WINNT=${_WIN32_WINNT_WIN10}
_WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_CO} _WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_NI}
) )
endif() endif()
if(MSVC) if(MSVC)

View File

@ -41,9 +41,6 @@ Q_LOGGING_CATEGORY(lcFramelessHelperQt, "wangwenx190.framelesshelper.core.impl.q
using namespace Global; using namespace Global;
FRAMELESSHELPER_BYTEARRAY_CONSTANT2(DontOverrideCursorVar, "FRAMELESSHELPER_DONT_OVERRIDE_CURSOR")
FRAMELESSHELPER_BYTEARRAY_CONSTANT2(DontToggleMaximizeVar, "FRAMELESSHELPER_DONT_TOGGLE_MAXIMIZE")
struct QtHelperData struct QtHelperData
{ {
SystemParameters params = {}; SystemParameters params = {};

View File

@ -72,8 +72,6 @@ FRAMELESSHELPER_STRING_CONSTANT(SetWindowPos)
FRAMELESSHELPER_STRING_CONSTANT(TrackMouseEvent) FRAMELESSHELPER_STRING_CONSTANT(TrackMouseEvent)
FRAMELESSHELPER_STRING_CONSTANT(FindWindowW) FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
FRAMELESSHELPER_STRING_CONSTANT(UnregisterClassW) FRAMELESSHELPER_STRING_CONSTANT(UnregisterClassW)
FRAMELESSHELPER_BYTEARRAY_CONSTANT2(DontOverrideCursorVar, "FRAMELESSHELPER_DONT_OVERRIDE_CURSOR")
FRAMELESSHELPER_BYTEARRAY_CONSTANT2(DontToggleMaximizeVar, "FRAMELESSHELPER_DONT_TOGGLE_MAXIMIZE")
FRAMELESSHELPER_STRING_CONSTANT(DestroyWindow) FRAMELESSHELPER_STRING_CONSTANT(DestroyWindow)
[[maybe_unused]] static constexpr const char kFallbackTitleBarErrorMessage[] = [[maybe_unused]] static constexpr const char kFallbackTitleBarErrorMessage[] =
"FramelessHelper is unable to create the fallback title bar window, and thus the snap layout feature will be disabled" "FramelessHelper is unable to create the fallback title bar window, and thus the snap layout feature will be disabled"
@ -524,15 +522,15 @@ void FramelessHelperWin::addWindow(const SystemParameters &params)
if (WindowsVersionHelper::isWin10RS1OrGreater()) { if (WindowsVersionHelper::isWin10RS1OrGreater()) {
// Tell DWM we may need dark theme non-client area (title bar & frame border). // Tell DWM we may need dark theme non-client area (title bar & frame border).
FramelessHelper::Core::setApplicationOSThemeAware(); FramelessHelper::Core::setApplicationOSThemeAware();
const bool dark = Utils::shouldAppsUseDarkMode();
Utils::updateWindowFrameBorderColor(windowId, dark);
if (WindowsVersionHelper::isWin10RS5OrGreater()) { if (WindowsVersionHelper::isWin10RS5OrGreater()) {
const bool dark = Utils::shouldAppsUseDarkMode();
static const bool isQtQuickApplication = (params.getCurrentApplicationType() == ApplicationType::Quick); static const bool isQtQuickApplication = (params.getCurrentApplicationType() == ApplicationType::Quick);
if (isQtQuickApplication) { if (isQtQuickApplication) {
// Tell UXTheme we may need dark theme controls. // Tell UXTheme we may need dark theme controls.
// Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications. // Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications.
Utils::updateGlobalWin32ControlsTheme(windowId, dark); Utils::updateGlobalWin32ControlsTheme(windowId, dark);
} }
Utils::refreshWin32ThemeResources(windowId, dark);
if (WindowsVersionHelper::isWin11OrGreater()) { if (WindowsVersionHelper::isWin11OrGreater()) {
const FramelessConfig * const config = FramelessConfig::instance(); const FramelessConfig * const config = FramelessConfig::instance();
// Set the frame corner style, only Win11 provides official public API to do it. // Set the frame corner style, only Win11 provides official public API to do it.
@ -1199,16 +1197,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
if ((wParam == 0) && (lParam != 0) // lParam sometimes may be NULL. if ((wParam == 0) && (lParam != 0) // lParam sometimes may be NULL.
&& (std::wcscmp(reinterpret_cast<LPCWSTR>(lParam), kThemeSettingChangeEventName) == 0)) { && (std::wcscmp(reinterpret_cast<LPCWSTR>(lParam), kThemeSettingChangeEventName) == 0)) {
systemThemeChanged = true; systemThemeChanged = true;
const bool dark = Utils::shouldAppsUseDarkMode();
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
Utils::updateWindowFrameBorderColor(windowId, dark);
#endif
if (WindowsVersionHelper::isWin10RS5OrGreater()) { if (WindowsVersionHelper::isWin10RS5OrGreater()) {
const bool dark = Utils::shouldAppsUseDarkMode();
static const bool isQtQuickApplication = (data.params.getCurrentApplicationType() == ApplicationType::Quick); static const bool isQtQuickApplication = (data.params.getCurrentApplicationType() == ApplicationType::Quick);
if (isQtQuickApplication) { if (isQtQuickApplication) {
// Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications. // Causes some QtWidgets paint incorrectly, so only apply to Qt Quick applications.
Utils::updateGlobalWin32ControlsTheme(windowId, dark); Utils::updateGlobalWin32ControlsTheme(windowId, dark);
} }
Utils::refreshWin32ThemeResources(windowId, dark);
} }
} }
} }

View File

@ -50,6 +50,20 @@ SysApiLoader *SysApiLoader::instance()
return g_sysApiLoader(); return g_sysApiLoader();
} }
QFunctionPointer SysApiLoader::resolve(const QString &library, const char *function)
{
Q_ASSERT(!library.isEmpty());
Q_ASSERT(function);
if (library.isEmpty() || !function) {
return nullptr;
}
#ifdef Q_OS_WINDOWS
return QSystemLibrary::resolve(library, function);
#else
return QLibrary::resolve(library, function.constData());
#endif
}
QFunctionPointer SysApiLoader::resolve(const QString &library, const QByteArray &function) QFunctionPointer SysApiLoader::resolve(const QString &library, const QByteArray &function)
{ {
Q_ASSERT(!library.isEmpty()); Q_ASSERT(!library.isEmpty());
@ -57,11 +71,7 @@ QFunctionPointer SysApiLoader::resolve(const QString &library, const QByteArray
if (library.isEmpty() || function.isEmpty()) { if (library.isEmpty() || function.isEmpty()) {
return nullptr; return nullptr;
} }
#ifdef Q_OS_WINDOWS return SysApiLoader::resolve(library, function.constData());
return QSystemLibrary::resolve(library, function.constData());
#else
return QLibrary::resolve(library, function.constData());
#endif
} }
QFunctionPointer SysApiLoader::resolve(const QString &library, const QString &function) QFunctionPointer SysApiLoader::resolve(const QString &library, const QString &function)

View File

@ -23,6 +23,9 @@
*/ */
#include "utils.h" #include "utils.h"
#ifdef Q_OS_WINDOWS
# include "winverhelper_p.h"
#endif
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
#include <QtGui/qscreen.h> #include <QtGui/qscreen.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
@ -140,8 +143,7 @@ QString Utils::getSystemButtonIconCode(const SystemButtonType button)
// Windows 11: Segoe Fluent Icons (https://docs.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font) // Windows 11: Segoe Fluent Icons (https://docs.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font)
// Windows 10: Segoe MDL2 Assets (https://docs.microsoft.com/en-us/windows/apps/design/style/segoe-ui-symbol-font) // Windows 10: Segoe MDL2 Assets (https://docs.microsoft.com/en-us/windows/apps/design/style/segoe-ui-symbol-font)
// Windows 7~8.1: Micon (http://xtoolkit.github.io/Micon/) // Windows 7~8.1: Micon (http://xtoolkit.github.io/Micon/)
static const bool isWin10OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1507); if (WindowsVersionHelper::isWin10OrGreater()) {
if (isWin10OrGreater) {
return QChar(icon.segoe); return QChar(icon.segoe);
} }
#endif #endif

View File

@ -42,9 +42,48 @@
#include "sysapiloader_p.h" #include "sysapiloader_p.h"
#include "registrykey_p.h" #include "registrykey_p.h"
#include "winverhelper_p.h" #include "winverhelper_p.h"
#include <uxtheme.h>
#include <d2d1.h> #include <d2d1.h>
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
GetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvData)
{
Q_ASSERT(hWnd);
Q_ASSERT(pvData);
if (!hWnd || !pvData) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(user32)
FRAMELESSHELPER_STRING_CONSTANT(GetWindowCompositionAttribute)
const auto loader = SysApiLoader::instance();
if (!loader->isAvailable(kuser32, kGetWindowCompositionAttribute)) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return (loader->get<GetWindowCompositionAttributePtr>(kGetWindowCompositionAttribute))(hWnd, pvData);
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
SetWindowCompositionAttribute(const HWND hWnd, PWINDOWCOMPOSITIONATTRIBDATA pvData)
{
Q_ASSERT(hWnd);
Q_ASSERT(pvData);
if (!hWnd || !pvData) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(user32)
FRAMELESSHELPER_STRING_CONSTANT(SetWindowCompositionAttribute)
const auto loader = SysApiLoader::instance();
if (!loader->isAvailable(kuser32, kSetWindowCompositionAttribute)) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return (loader->get<SetWindowCompositionAttributePtr>(kSetWindowCompositionAttribute))(hWnd, pvData);
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API HRESULT WINAPI EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API HRESULT WINAPI
SetWindowThemeAttribute2(const HWND hWnd, const _WINDOWTHEMEATTRIBUTETYPE attrib, SetWindowThemeAttribute2(const HWND hWnd, const _WINDOWTHEMEATTRIBUTETYPE attrib,
PVOID pvData, const DWORD cbData PVOID pvData, const DWORD cbData
@ -55,13 +94,14 @@ SetWindowThemeAttribute2(const HWND hWnd, const _WINDOWTHEMEATTRIBUTETYPE attrib
if (!hWnd || !pvData) { if (!hWnd || !pvData) {
return E_INVALIDARG; return E_INVALIDARG;
} }
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme) FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
FRAMELESSHELPER_STRING_CONSTANT(SetWindowThemeAttribute) FRAMELESSHELPER_STRING_CONSTANT(SetWindowThemeAttribute)
const auto loader = FRAMELESSHELPER_PREPEND_NAMESPACE(SysApiLoader)::instance(); const auto loader = SysApiLoader::instance();
if (!loader->isAvailable(kuxtheme, kSetWindowThemeAttribute)) { if (!loader->isAvailable(kuxtheme, kSetWindowThemeAttribute)) {
return E_NOTIMPL; return E_NOTIMPL;
} }
return (loader->get<decltype(&::SetWindowThemeAttribute2)>(kSetWindowThemeAttribute))(hWnd, attrib, pvData, cbData); return (loader->get<decltype(&SetWindowThemeAttribute2)>(kSetWindowThemeAttribute))(hWnd, attrib, pvData, cbData);
} }
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API HRESULT WINAPI EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API HRESULT WINAPI
@ -73,6 +113,187 @@ SetWindowThemeNonClientAttributes2(const HWND hWnd, const DWORD dwMask, const DW
return SetWindowThemeAttribute2(hWnd, _WTA_NONCLIENT, &options, sizeof(options)); return SetWindowThemeAttribute2(hWnd, _WTA_NONCLIENT, &options, sizeof(options));
} }
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
ShouldAppsUseDarkMode(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pShouldAppsUseDarkMode
= reinterpret_cast<ShouldAppsUseDarkModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(132)));
if (!pShouldAppsUseDarkMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pShouldAppsUseDarkMode();
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
AllowDarkModeForWindow(const HWND hWnd, const BOOL bAllow)
{
Q_ASSERT(hWnd);
if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pAllowDarkModeForWindow
= reinterpret_cast<AllowDarkModeForWindowPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(133)));
if (!pAllowDarkModeForWindow) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pAllowDarkModeForWindow(hWnd, bAllow);
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
AllowDarkModeForApp(const BOOL bAllow)
{
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pAllowDarkModeForApp
= reinterpret_cast<AllowDarkModeForAppPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135)));
if (!pAllowDarkModeForApp) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pAllowDarkModeForApp(bAllow);
}
EXTERN_C FRAMELESSHELPER_CORE_API VOID WINAPI
FlushMenuThemes(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pFlushMenuThemes
= reinterpret_cast<FlushMenuThemesPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(136)));
if (!pFlushMenuThemes) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return;
}
pFlushMenuThemes();
}
EXTERN_C FRAMELESSHELPER_CORE_API VOID WINAPI
RefreshImmersiveColorPolicyState(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pRefreshImmersiveColorPolicyState
= reinterpret_cast<RefreshImmersiveColorPolicyStatePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(104)));
if (!pRefreshImmersiveColorPolicyState) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return;
}
pRefreshImmersiveColorPolicyState();
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
IsDarkModeAllowedForWindow(const HWND hWnd)
{
Q_ASSERT(hWnd);
if (!hWnd) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pIsDarkModeAllowedForWindow
= reinterpret_cast<IsDarkModeAllowedForWindowPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(137)));
if (!pIsDarkModeAllowedForWindow) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pIsDarkModeAllowedForWindow(hWnd);
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
GetIsImmersiveColorUsingHighContrast(const IMMERSIVE_HC_CACHE_MODE mode)
{
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pGetIsImmersiveColorUsingHighContrast
= reinterpret_cast<GetIsImmersiveColorUsingHighContrastPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(106)));
if (!pGetIsImmersiveColorUsingHighContrast) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pGetIsImmersiveColorUsingHighContrast(mode);
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API HTHEME WINAPI
OpenNcThemeData(const HWND hWnd, LPCWSTR pszClassList)
{
Q_ASSERT(hWnd);
Q_ASSERT(pszClassList);
if (!hWnd || !pszClassList) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pOpenNcThemeData
= reinterpret_cast<OpenNcThemeDataPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(49)));
if (!pOpenNcThemeData) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pOpenNcThemeData(hWnd, pszClassList);
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
ShouldSystemUseDarkMode(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pShouldSystemUseDarkMode
= reinterpret_cast<ShouldSystemUseDarkModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(138)));
if (!pShouldSystemUseDarkMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pShouldSystemUseDarkMode();
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API PREFERRED_APP_MODE WINAPI
SetPreferredAppMode(const PREFERRED_APP_MODE mode)
{
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pSetPreferredAppMode
= reinterpret_cast<SetPreferredAppModePtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(135)));
if (!pSetPreferredAppMode) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return PAM_MAX;
}
return pSetPreferredAppMode(mode);
}
EXTERN_C [[nodiscard]] FRAMELESSHELPER_CORE_API BOOL WINAPI
IsDarkModeAllowedForApp(VOID)
{
FRAMELESSHELPER_USE_NAMESPACE
FRAMELESSHELPER_STRING_CONSTANT(uxtheme)
static const auto pIsDarkModeAllowedForApp
= reinterpret_cast<IsDarkModeAllowedForAppPtr>(
SysApiLoader::resolve(kuxtheme, MAKEINTRESOURCEA(139)));
if (!pIsDarkModeAllowedForApp) {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
return pIsDarkModeAllowedForApp();
}
Q_DECLARE_METATYPE(QMargins) Q_DECLARE_METATYPE(QMargins)
FRAMELESSHELPER_BEGIN_NAMESPACE FRAMELESSHELPER_BEGIN_NAMESPACE
@ -169,6 +390,11 @@ FRAMELESSHELPER_STRING_CONSTANT(DeleteDC)
FRAMELESSHELPER_STRING_CONSTANT(d2d1) FRAMELESSHELPER_STRING_CONSTANT(d2d1)
FRAMELESSHELPER_STRING_CONSTANT(D2D1CreateFactory) FRAMELESSHELPER_STRING_CONSTANT(D2D1CreateFactory)
FRAMELESSHELPER_STRING_CONSTANT(ReloadSystemMetrics) FRAMELESSHELPER_STRING_CONSTANT(ReloadSystemMetrics)
FRAMELESSHELPER_STRING_CONSTANT(SetPreferredAppMode)
FRAMELESSHELPER_STRING_CONSTANT(AllowDarkModeForApp)
FRAMELESSHELPER_STRING_CONSTANT(AllowDarkModeForWindow)
FRAMELESSHELPER_STRING_CONSTANT(FlushMenuThemes)
FRAMELESSHELPER_STRING_CONSTANT(RefreshImmersiveColorPolicyState)
struct Win32UtilsHelperData struct Win32UtilsHelperData
{ {
@ -474,8 +700,7 @@ bool Utils::isWindowsVersionOrGreater(const WindowsVersion version)
bool Utils::isDwmCompositionEnabled() bool Utils::isDwmCompositionEnabled()
{ {
// 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.
static const bool isWin8OrGreater = isWindowsVersionOrGreater(WindowsVersion::_8); if (WindowsVersionHelper::isWin8OrGreater()) {
if (isWin8OrGreater) {
return true; return true;
} }
const auto resultFromRegistry = []() -> bool { const auto resultFromRegistry = []() -> bool {
@ -627,8 +852,7 @@ QColor Utils::getDwmColorizationColor()
DwmColorizationArea Utils::getDwmColorizationArea() DwmColorizationArea Utils::getDwmColorizationArea()
{ {
// It's a Win10 only feature. (TO BE VERIFIED) // It's a Win10 only feature. (TO BE VERIFIED)
static const bool isWin10OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1507); if (!WindowsVersionHelper::isWin10OrGreater()) {
if (!isWin10OrGreater) {
return DwmColorizationArea::None_; return DwmColorizationArea::None_;
} }
const RegistryKey themeRegistry(RegistryRootKey::CurrentUser, personalizeRegistryKey()); const RegistryKey themeRegistry(RegistryRootKey::CurrentUser, personalizeRegistryKey());
@ -1035,8 +1259,7 @@ quint32 Utils::getFrameBorderThickness(const WId windowId, const bool scaled)
return 0; return 0;
} }
// There's no window frame border before Windows 10. // There's no window frame border before Windows 10.
static const bool isWin10OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1507); if (!WindowsVersionHelper::isWin10OrGreater()) {
if (!isWin10OrGreater) {
return 0; return 0;
} }
if (!API_DWM_AVAILABLE(DwmGetWindowAttribute)) { if (!API_DWM_AVAILABLE(DwmGetWindowAttribute)) {
@ -1061,8 +1284,7 @@ QColor Utils::getFrameBorderColor(const bool active)
{ {
// There's no window frame border before Windows 10. // There's no window frame border before Windows 10.
// So we just return a default value which is based on most window managers. // So we just return a default value which is based on most window managers.
static const bool isWin10OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1507); if (!WindowsVersionHelper::isWin10OrGreater()) {
if (!isWin10OrGreater) {
return (active ? kDefaultBlackColor : kDefaultDarkGrayColor); return (active ? kDefaultBlackColor : kDefaultDarkGrayColor);
} }
const bool dark = shouldAppsUseDarkMode(); const bool dark = shouldAppsUseDarkMode();
@ -1077,30 +1299,6 @@ QColor Utils::getFrameBorderColor(const bool active)
} }
} }
void Utils::updateWindowFrameBorderColor(const WId windowId, const bool dark)
{
Q_ASSERT(windowId);
if (!windowId) {
return;
}
// There's no global dark theme before Win10 1607.
static const bool isWin10RS1OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1607);
if (!isWin10RS1OrGreater) {
return;
}
if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) {
return;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
static const bool isWin1020H1OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_2004);
const DWORD mode = (isWin1020H1OrGreater ? _DWMWA_USE_IMMERSIVE_DARK_MODE : _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1);
const BOOL value = (dark ? TRUE : FALSE);
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd, mode, &value, sizeof(value));
if (FAILED(hr)) {
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
}
}
void Utils::maybeFixupQtInternals(const WId windowId) void Utils::maybeFixupQtInternals(const WId windowId)
{ {
Q_ASSERT(windowId); Q_ASSERT(windowId);
@ -1216,8 +1414,7 @@ bool Utils::isWindowFrameBorderVisible()
if (config->isSet(Option::ForceHideWindowFrameBorder)) { if (config->isSet(Option::ForceHideWindowFrameBorder)) {
return false; return false;
} }
static const bool isWin10OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1507); return WindowsVersionHelper::isWin10OrGreater();
return isWin10OrGreater;
}(); }();
return result; return result;
} }
@ -1225,8 +1422,7 @@ bool Utils::isWindowFrameBorderVisible()
bool Utils::isTitleBarColorized() bool Utils::isTitleBarColorized()
{ {
// CHECK: is it supported on win7? // CHECK: is it supported on win7?
static const bool isWin10OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1507); if (!WindowsVersionHelper::isWin10OrGreater()) {
if (!isWin10OrGreater) {
return false; return false;
} }
const DwmColorizationArea area = getDwmColorizationArea(); const DwmColorizationArea area = getDwmColorizationArea();
@ -1407,8 +1603,7 @@ SystemTheme Utils::getSystemTheme()
if (isHighContrastModeEnabled()) { if (isHighContrastModeEnabled()) {
return SystemTheme::HighContrast; return SystemTheme::HighContrast;
} }
static const bool isWin10RS1OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1607); if (WindowsVersionHelper::isWin10RS1OrGreater() && shouldAppsUseDarkMode()) {
if (isWin10RS1OrGreater && shouldAppsUseDarkMode()) {
return SystemTheme::Dark; return SystemTheme::Dark;
} }
return SystemTheme::Light; return SystemTheme::Light;
@ -1421,8 +1616,7 @@ void Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
return; return;
} }
// There's no global dark theme for common Win32 controls before Win10 1809. // There's no global dark theme for common Win32 controls before Win10 1809.
static const bool isWin10RS5OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1809); if (!WindowsVersionHelper::isWin10RS5OrGreater()) {
if (!isWin10RS5OrGreater) {
return; return;
} }
if (!API_THEME_AVAILABLE(SetWindowTheme)) { if (!API_THEME_AVAILABLE(SetWindowTheme)) {
@ -1439,8 +1633,7 @@ void Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
bool Utils::shouldAppsUseDarkMode_windows() bool Utils::shouldAppsUseDarkMode_windows()
{ {
// The global dark mode was first introduced in Windows 10 1607. // The global dark mode was first introduced in Windows 10 1607.
static const bool isWin10RS1OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1607); if (!WindowsVersionHelper::isWin10RS1OrGreater()) {
if (!isWin10RS1OrGreater) {
return false; return false;
} }
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
@ -1486,8 +1679,7 @@ void Utils::forceSquareCornersForWindow(const WId windowId, const bool force)
return; return;
} }
// We cannot change the window corner style until Windows 11. // We cannot change the window corner style until Windows 11.
static const bool isWin11OrGreater = isWindowsVersionOrGreater(WindowsVersion::_11_21H2); if (!WindowsVersionHelper::isWin11OrGreater()) {
if (!isWin11OrGreater) {
return; return;
} }
if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) { if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) {
@ -1508,44 +1700,34 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
return false; return false;
} }
const auto hwnd = reinterpret_cast<HWND>(windowId); const auto hwnd = reinterpret_cast<HWND>(windowId);
static const bool isWin8OrGreater = isWindowsVersionOrGreater(WindowsVersion::_8); if (WindowsVersionHelper::isWin8OrGreater()) {
if (isWin8OrGreater) {
if (!API_USER_AVAILABLE(SetWindowCompositionAttribute)) {
return false;
}
if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) { if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) {
return false; return false;
} }
if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) { if (!API_DWM_AVAILABLE(DwmExtendFrameIntoClientArea)) {
return false; return false;
} }
const auto pSetWindowCompositionAttribute =
reinterpret_cast<SetWindowCompositionAttributePtr>(
SysApiLoader::instance()->get(kSetWindowCompositionAttribute));
static const bool isWin1122H2OrGreater = isWindowsVersionOrGreater(WindowsVersion::_11_22H2);
static const bool isWin11OrGreater = isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
static const bool isWin10OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1507);
const BlurMode blurMode = [mode]() -> BlurMode { const BlurMode blurMode = [mode]() -> BlurMode {
if ((mode == BlurMode::Disable) || (mode == BlurMode::Windows_Aero)) { if ((mode == BlurMode::Disable) || (mode == BlurMode::Windows_Aero)) {
return mode; return mode;
} }
if ((mode == BlurMode::Windows_Mica) && !isWin11OrGreater) { if ((mode == BlurMode::Windows_Mica) && !WindowsVersionHelper::isWin11OrGreater()) {
WARNING << "The Mica material is not supported on your system, fallback to the Acrylic blur instead..."; WARNING << "The Mica material is not supported on your system, fallback to the Acrylic blur instead...";
if (isWin10OrGreater) { if (WindowsVersionHelper::isWin10OrGreater()) {
return BlurMode::Windows_Acrylic; return BlurMode::Windows_Acrylic;
} }
WARNING << "The Acrylic blur is not supported on your system, fallback to the traditional DWM blur instead..."; WARNING << "The Acrylic blur is not supported on your system, fallback to the traditional DWM blur instead...";
return BlurMode::Windows_Aero; return BlurMode::Windows_Aero;
} }
if ((mode == BlurMode::Windows_Acrylic) && !isWin10OrGreater) { if ((mode == BlurMode::Windows_Acrylic) && !WindowsVersionHelper::isWin10OrGreater()) {
WARNING << "The Acrylic blur is not supported on your system, fallback to the traditional DWM blur instead..."; WARNING << "The Acrylic blur is not supported on your system, fallback to the traditional DWM blur instead...";
return BlurMode::Windows_Aero; return BlurMode::Windows_Aero;
} }
if (mode == BlurMode::Default) { if (mode == BlurMode::Default) {
if (isWin11OrGreater) { if (WindowsVersionHelper::isWin11OrGreater()) {
return BlurMode::Windows_Mica; return BlurMode::Windows_Mica;
} }
if (isWin10OrGreater) { if (WindowsVersionHelper::isWin10OrGreater()) {
return BlurMode::Windows_Acrylic; return BlurMode::Windows_Acrylic;
} }
return BlurMode::Windows_Aero; return BlurMode::Windows_Aero;
@ -1554,7 +1736,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
return mode; return mode;
}(); }();
if (blurMode == BlurMode::Disable) { if (blurMode == BlurMode::Disable) {
if (isWin1122H2OrGreater) { if (WindowsVersionHelper::isWin1122H2OrGreater()) {
const _DWM_SYSTEMBACKDROP_TYPE dwmsbt = _DWMSBT_NONE; const _DWM_SYSTEMBACKDROP_TYPE dwmsbt = _DWMSBT_NONE;
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute,
hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt)); hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt));
@ -1562,7 +1744,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr); WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
} }
} }
if (isWin11OrGreater) { if (WindowsVersionHelper::isWin11OrGreater()) {
const BOOL enable = FALSE; const BOOL enable = FALSE;
HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute,
hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable)); hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable));
@ -1583,7 +1765,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
wcad.Attrib = WCA_ACCENT_POLICY; wcad.Attrib = WCA_ACCENT_POLICY;
wcad.pvData = &policy; wcad.pvData = &policy;
wcad.cbData = sizeof(policy); wcad.cbData = sizeof(policy);
if (pSetWindowCompositionAttribute(hwnd, &wcad) == FALSE) { if (SetWindowCompositionAttribute(hwnd, &wcad) == FALSE) {
WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute); WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute);
} }
} }
@ -1597,7 +1779,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
const MARGINS margins = {-1, -1, -1, -1}; const MARGINS margins = {-1, -1, -1, -1};
HRESULT hr = API_CALL_FUNCTION(DwmExtendFrameIntoClientArea, hwnd, &margins); HRESULT hr = API_CALL_FUNCTION(DwmExtendFrameIntoClientArea, hwnd, &margins);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
if (isWin1122H2OrGreater) { if (WindowsVersionHelper::isWin1122H2OrGreater()) {
const _DWM_SYSTEMBACKDROP_TYPE dwmsbt = _DWMSBT_MAINWINDOW; // Mica const _DWM_SYSTEMBACKDROP_TYPE dwmsbt = _DWMSBT_MAINWINDOW; // Mica
hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd, hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd,
_DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt)); _DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt));
@ -1646,8 +1828,8 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
wcad.Attrib = WCA_ACCENT_POLICY; wcad.Attrib = WCA_ACCENT_POLICY;
wcad.pvData = &policy; wcad.pvData = &policy;
wcad.cbData = sizeof(policy); wcad.cbData = sizeof(policy);
if (pSetWindowCompositionAttribute(hwnd, &wcad) != FALSE) { if (SetWindowCompositionAttribute(hwnd, &wcad) != FALSE) {
if (!isWin11OrGreater) { if (!WindowsVersionHelper::isWin11OrGreater()) {
DEBUG << "Enabling the Acrylic blur for Win32 windows on Windows 10 " DEBUG << "Enabling the Acrylic blur for Win32 windows on Windows 10 "
"is very buggy. The only recommended way by Microsoft is to " "is very buggy. The only recommended way by Microsoft is to "
"use the XAML Island technology or use pure UWP instead. If " "use the XAML Island technology or use pure UWP instead. If "
@ -1749,8 +1931,7 @@ bool Utils::isBlurBehindWindowSupported()
if (FramelessConfig::instance()->isSet(Option::ForceNonNativeBackgroundBlur)) { if (FramelessConfig::instance()->isSet(Option::ForceNonNativeBackgroundBlur)) {
return false; return false;
} }
static const bool isWin11OrGreater = isWindowsVersionOrGreater(WindowsVersion::_11_21H2); return WindowsVersionHelper::isWin11OrGreater();
return isWin11OrGreater;
}(); }();
return result; return result;
} }
@ -1817,4 +1998,98 @@ void Utils::registerThemeChangeNotification()
// top level windows by default. // top level windows by default.
} }
void Utils::refreshWin32ThemeResources(const WId windowId, const bool dark)
{
Q_ASSERT(windowId);
if (!windowId) {
return;
}
// We have no way to adjust such things until Win10 1809.
if (!WindowsVersionHelper::isWin10RS5OrGreater()) {
return;
}
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
if (!API_DWM_AVAILABLE(DwmSetWindowAttribute)) {
return;
}
#endif
const auto hWnd = reinterpret_cast<HWND>(windowId);
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
const DWORD borderFlag = (WindowsVersionHelper::isWin1020H1OrGreater()
? _DWMWA_USE_IMMERSIVE_DARK_MODE : _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1);
#endif
const PREFERRED_APP_MODE appMode = (dark ? PAM_ALLOW_DARK : PAM_DEFAULT);
const BOOL darkFlag = (dark ? TRUE : FALSE);
WINDOWCOMPOSITIONATTRIBDATA wcad;
SecureZeroMemory(&wcad, sizeof(wcad));
wcad.Attrib = WCA_USEDARKMODECOLORS;
wcad.pvData = const_cast<BOOL *>(&darkFlag);
wcad.cbData = sizeof(darkFlag);
if (dark) {
if (WindowsVersionHelper::isWin1019H1OrGreater()) {
if (SetPreferredAppMode(appMode) == PAM_MAX) {
WARNING << getSystemErrorMessage(kSetPreferredAppMode);
}
} else {
if (AllowDarkModeForApp(darkFlag) == FALSE) {
WARNING << getSystemErrorMessage(kAllowDarkModeForApp);
}
}
if (AllowDarkModeForWindow(hWnd, darkFlag) == FALSE) {
WARNING << getSystemErrorMessage(kAllowDarkModeForWindow);
}
if (SetWindowCompositionAttribute(hWnd, &wcad) == FALSE) {
WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute);
}
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hWnd, borderFlag, &darkFlag, sizeof(darkFlag));
if (FAILED(hr)) {
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
}
#endif
SetLastError(ERROR_SUCCESS);
FlushMenuThemes();
if (GetLastError() != ERROR_SUCCESS) {
WARNING << getSystemErrorMessage(kFlushMenuThemes);
}
SetLastError(ERROR_SUCCESS);
RefreshImmersiveColorPolicyState();
if (GetLastError() != ERROR_SUCCESS) {
WARNING << getSystemErrorMessage(kRefreshImmersiveColorPolicyState);
}
} else {
if (AllowDarkModeForWindow(hWnd, darkFlag) == FALSE) {
WARNING << getSystemErrorMessage(kAllowDarkModeForWindow);
}
if (SetWindowCompositionAttribute(hWnd, &wcad) == FALSE) {
WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute);
}
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hWnd, borderFlag, &darkFlag, sizeof(darkFlag));
if (FAILED(hr)) {
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
}
#endif
SetLastError(ERROR_SUCCESS);
FlushMenuThemes();
if (GetLastError() != ERROR_SUCCESS) {
WARNING << getSystemErrorMessage(kFlushMenuThemes);
}
SetLastError(ERROR_SUCCESS);
RefreshImmersiveColorPolicyState();
if (GetLastError() != ERROR_SUCCESS) {
WARNING << getSystemErrorMessage(kRefreshImmersiveColorPolicyState);
}
if (WindowsVersionHelper::isWin1019H1OrGreater()) {
if (SetPreferredAppMode(appMode) == PAM_MAX) {
WARNING << getSystemErrorMessage(kSetPreferredAppMode);
}
} else {
if (AllowDarkModeForApp(darkFlag) == FALSE) {
WARNING << getSystemErrorMessage(kAllowDarkModeForApp);
}
}
}
}
FRAMELESSHELPER_END_NAMESPACE FRAMELESSHELPER_END_NAMESPACE

View File

@ -29,14 +29,14 @@ target_sources(${PROJECT_NAME} PRIVATE
) )
set(_WIN32_WINNT_WIN10 0x0A00) set(_WIN32_WINNT_WIN10 0x0A00)
set(NTDDI_WIN10_CO 0x0A00000B) set(NTDDI_WIN10_NI 0x0A00000C)
target_compile_definitions(${PROJECT_NAME} PRIVATE target_compile_definitions(${PROJECT_NAME} PRIVATE
_CRT_NON_CONFORMING_SWPRINTFS _CRT_SECURE_NO_WARNINGS _CRT_NON_CONFORMING_SWPRINTFS _CRT_SECURE_NO_WARNINGS
_CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_WARNINGS
_CRT_NONSTDC_NO_DEPRECATE _ENABLE_EXTENDED_ALIGNED_STORAGE _CRT_NONSTDC_NO_DEPRECATE _ENABLE_EXTENDED_ALIGNED_STORAGE
NOMINMAX UNICODE _UNICODE WIN32_LEAN_AND_MEAN WINRT_LEAN_AND_MEAN NOMINMAX UNICODE _UNICODE WIN32_LEAN_AND_MEAN WINRT_LEAN_AND_MEAN
WINVER=${_WIN32_WINNT_WIN10} _WIN32_WINNT=${_WIN32_WINNT_WIN10} WINVER=${_WIN32_WINNT_WIN10} _WIN32_WINNT=${_WIN32_WINNT_WIN10}
_WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_CO} _WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_NI}
) )
target_compile_options(${PROJECT_NAME} PRIVATE target_compile_options(${PROJECT_NAME} PRIVATE