From 327055934009dc416be6234db8e4d26fab81fb80 Mon Sep 17 00:00:00 2001 From: SineStriker <55847490+SineStriker@users.noreply.github.com> Date: ćšć, 21 12æ 2023 23:21:28 +0800 Subject: [PATCH] Merge pull request #8 from stdware/stylesupport --- src/core/shared/qwkwindowsextra_p.h | 386 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 386 insertions(+), 0 deletions(-) diff --git a/src/core/shared/qwkwindowsextra_p.h b/src/core/shared/qwkwindowsextra_p.h new file mode 100644 index 0000000..03adf7e --- /dev/null +++ b/src/core/shared/qwkwindowsextra_p.h @@ -0,0 +1,386 @@ +#ifndef QWKWINDOWSEXTRA_P_H +#define QWKWINDOWSEXTRA_P_H + +// +// W A R N I N G !!! +// ----------------- +// +// This file is not part of the QWindowKit API. It is used purely as an +// implementation detail. This header file may change from version to +// version without notice, or may even be removed. +// + +#include <shellscalingapi.h> +#include <dwmapi.h> +#include <timeapi.h> + +#include <QWKCore/qwindowkit_windows.h> + +#include <QtCore/private/qsystemlibrary_p.h> +#include <QtCore/private/qwinregistry_p.h> + +#include <QtGui/QStyleHints> +#include <QtGui/QPalette> + +// Don't include this header in any header files. + +namespace QWK { + + enum _DWMWINDOWATTRIBUTE { + // [set] BOOL, Allows the use of host backdrop brushes for the window. + _DWMWA_USE_HOSTBACKDROPBRUSH = 17, + + // Undocumented, the same with DWMWA_USE_IMMERSIVE_DARK_MODE, but available on systems + // before Win10 20H1. + _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, + + // [set] BOOL, Allows a window to either use the accent color, or dark, according to the + // user Color Mode preferences. + _DWMWA_USE_IMMERSIVE_DARK_MODE = 20, + + // [set] WINDOW_CORNER_PREFERENCE, Controls the policy that rounds top-level window corners + _DWMWA_WINDOW_CORNER_PREFERENCE = 33, + + // [get] UINT, width of the visible border around a thick frame window + _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37, + + // [get, set] SYSTEMBACKDROP_TYPE, Controls the system-drawn backdrop material of a window, + // including behind the non-client area. + _DWMWA_SYSTEMBACKDROP_TYPE = 38, + + // Undocumented, use this value to enable Mica material on Win11 21H2. You should use + // DWMWA_SYSTEMBACKDROP_TYPE instead on Win11 22H2 and newer. + _DWMWA_MICA_EFFECT = 1029 + }; + + // Types used with DWMWA_SYSTEMBACKDROP_TYPE + enum _DWM_SYSTEMBACKDROP_TYPE { + _DWMSBT_AUTO, // [Default] Let DWM automatically decide the system-drawn backdrop for this + // window. + _DWMSBT_NONE, // [Disable] Do not draw any system backdrop. + _DWMSBT_MAINWINDOW, // [Mica] Draw the backdrop material effect corresponding to a + // long-lived window. + _DWMSBT_TRANSIENTWINDOW, // [Acrylic] Draw the backdrop material effect corresponding to a + // transient window. + _DWMSBT_TABBEDWINDOW, // [Mica Alt] Draw the backdrop material effect corresponding to a + // window with a tabbed title bar. + }; + + enum WINDOWCOMPOSITIONATTRIB { + WCA_UNDEFINED = 0, + WCA_NCRENDERING_ENABLED = 1, + WCA_NCRENDERING_POLICY = 2, + WCA_TRANSITIONS_FORCEDISABLED = 3, + WCA_ALLOW_NCPAINT = 4, + WCA_CAPTION_BUTTON_BOUNDS = 5, + WCA_NONCLIENT_RTL_LAYOUT = 6, + WCA_FORCE_ICONIC_REPRESENTATION = 7, + WCA_EXTENDED_FRAME_BOUNDS = 8, + WCA_HAS_ICONIC_BITMAP = 9, + WCA_THEME_ATTRIBUTES = 10, + WCA_NCRENDERING_EXILED = 11, + WCA_NCADORNMENTINFO = 12, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, + WCA_VIDEO_OVERLAY_ACTIVE = 14, + WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, + WCA_DISALLOW_PEEK = 16, + WCA_CLOAK = 17, + WCA_CLOAKED = 18, + WCA_ACCENT_POLICY = 19, + WCA_FREEZE_REPRESENTATION = 20, + WCA_EVER_UNCLOAKED = 21, + WCA_VISUAL_OWNER = 22, + WCA_HOLOGRAPHIC = 23, + WCA_EXCLUDED_FROM_DDA = 24, + WCA_PASSIVEUPDATEMODE = 25, + WCA_USEDARKMODECOLORS = 26, + WCA_CORNER_STYLE = 27, + WCA_PART_COLOR = 28, + WCA_DISABLE_MOVESIZE_FEEDBACK = 29, + WCA_LAST = 30 + }; + + enum ACCENT_STATE { + ACCENT_DISABLED = 0, + ACCENT_ENABLE_GRADIENT = 1, + ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, + ACCENT_ENABLE_BLURBEHIND = 3, // Traditional DWM blur + ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803 + ACCENT_ENABLE_HOST_BACKDROP = 5, // RS5 1809 + ACCENT_INVALID_STATE = 6 // Using this value will remove the window background + }; + + enum ACCENT_FLAG { + ACCENT_NONE = 0, + ACCENT_ENABLE_ACRYLIC = 1, + ACCENT_ENABLE_ACRYLIC_WITH_LUMINOSITY = 482 + }; + + struct ACCENT_POLICY { + DWORD dwAccentState; + DWORD dwAccentFlags; + DWORD dwGradientColor; // #AABBGGRR + DWORD dwAnimationId; + }; + using PACCENT_POLICY = ACCENT_POLICY *; + + struct WINDOWCOMPOSITIONATTRIBDATA { + WINDOWCOMPOSITIONATTRIB Attrib; + PVOID pvData; + SIZE_T cbData; + }; + using PWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA *; + + using SetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, PWINDOWCOMPOSITIONATTRIBDATA); + + namespace { + + struct DynamicApis { + static const DynamicApis &instance() { + static const DynamicApis inst{}; + return inst; + } + +#define DYNAMIC_API_DECLARE(NAME) decltype(&::NAME) p##NAME = nullptr + + DYNAMIC_API_DECLARE(DwmFlush); + DYNAMIC_API_DECLARE(DwmIsCompositionEnabled); + DYNAMIC_API_DECLARE(DwmGetCompositionTimingInfo); + DYNAMIC_API_DECLARE(DwmGetWindowAttribute); + DYNAMIC_API_DECLARE(DwmSetWindowAttribute); + DYNAMIC_API_DECLARE(DwmExtendFrameIntoClientArea); + DYNAMIC_API_DECLARE(DwmEnableBlurBehindWindow); + DYNAMIC_API_DECLARE(GetDpiForWindow); + DYNAMIC_API_DECLARE(GetSystemMetricsForDpi); + DYNAMIC_API_DECLARE(GetDpiForMonitor); + DYNAMIC_API_DECLARE(timeGetDevCaps); + DYNAMIC_API_DECLARE(timeBeginPeriod); + DYNAMIC_API_DECLARE(timeEndPeriod); + +#undef DYNAMIC_API_DECLARE + + SetWindowCompositionAttributePtr pSetWindowCompositionAttribute = nullptr; + + private: + DynamicApis() { +#define DYNAMIC_API_RESOLVE(DLL, NAME) \ + p##NAME = reinterpret_cast<decltype(p##NAME)>(DLL.resolve(#NAME)) + + QSystemLibrary user32(QStringLiteral("user32")); + DYNAMIC_API_RESOLVE(user32, GetDpiForWindow); + DYNAMIC_API_RESOLVE(user32, GetSystemMetricsForDpi); + DYNAMIC_API_RESOLVE(user32, SetWindowCompositionAttribute); + + QSystemLibrary shcore(QStringLiteral("shcore")); + DYNAMIC_API_RESOLVE(shcore, GetDpiForMonitor); + + QSystemLibrary dwmapi(QStringLiteral("dwmapi")); + DYNAMIC_API_RESOLVE(dwmapi, DwmFlush); + DYNAMIC_API_RESOLVE(dwmapi, DwmIsCompositionEnabled); + DYNAMIC_API_RESOLVE(dwmapi, DwmGetCompositionTimingInfo); + DYNAMIC_API_RESOLVE(dwmapi, DwmGetWindowAttribute); + DYNAMIC_API_RESOLVE(dwmapi, DwmSetWindowAttribute); + DYNAMIC_API_RESOLVE(dwmapi, DwmExtendFrameIntoClientArea); + DYNAMIC_API_RESOLVE(dwmapi, DwmEnableBlurBehindWindow); + + QSystemLibrary winmm(QStringLiteral("winmm")); + DYNAMIC_API_RESOLVE(winmm, timeGetDevCaps); + DYNAMIC_API_RESOLVE(winmm, timeBeginPeriod); + DYNAMIC_API_RESOLVE(winmm, timeEndPeriod); + +#undef DYNAMIC_API_RESOLVE + } + + ~DynamicApis() = default; + + Q_DISABLE_COPY_MOVE(DynamicApis) + }; + + } + + static inline constexpr bool operator==(const POINT &lhs, const POINT &rhs) noexcept { + return ((lhs.x == rhs.x) && (lhs.y == rhs.y)); + } + + static inline constexpr bool operator!=(const POINT &lhs, const POINT &rhs) noexcept { + return !operator==(lhs, rhs); + } + + static inline constexpr bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept { + return ((lhs.cx == rhs.cx) && (lhs.cy == rhs.cy)); + } + + static inline constexpr bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept { + return !operator==(lhs, rhs); + } + + static inline constexpr bool operator>(const SIZE &lhs, const SIZE &rhs) noexcept { + return ((lhs.cx * lhs.cy) > (rhs.cx * rhs.cy)); + } + + static inline constexpr bool operator>=(const SIZE &lhs, const SIZE &rhs) noexcept { + return (operator>(lhs, rhs) || operator==(lhs, rhs)); + } + + static inline constexpr bool operator<(const SIZE &lhs, const SIZE &rhs) noexcept { + return (operator!=(lhs, rhs) && !operator>(lhs, rhs)); + } + + static inline constexpr bool operator<=(const SIZE &lhs, const SIZE &rhs) noexcept { + return (operator<(lhs, rhs) || operator==(lhs, rhs)); + } + + static inline constexpr bool operator==(const RECT &lhs, const RECT &rhs) noexcept { + return ((lhs.left == rhs.left) && (lhs.top == rhs.top) && (lhs.right == rhs.right) && + (lhs.bottom == rhs.bottom)); + } + + static inline constexpr bool operator!=(const RECT &lhs, const RECT &rhs) noexcept { + return !operator==(lhs, rhs); + } + + static inline constexpr QPoint point2qpoint(const POINT &point) { + return QPoint{int(point.x), int(point.y)}; + } + + static inline constexpr POINT qpoint2point(const QPoint &point) { + return POINT{LONG(point.x()), LONG(point.y())}; + } + + static inline constexpr QSize size2qsize(const SIZE &size) { + return QSize{int(size.cx), int(size.cy)}; + } + + static inline constexpr SIZE qsize2size(const QSize &size) { + return SIZE{LONG(size.width()), LONG(size.height())}; + } + + static inline constexpr QRect rect2qrect(const RECT &rect) { + return QRect{ + QPoint{int(rect.left), int(rect.top) }, + QSize{int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect))} + }; + } + + static inline constexpr RECT qrect2rect(const QRect &qrect) { + return RECT{LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), + LONG(qrect.bottom())}; + } + + static inline /*constexpr*/ QString hwnd2str(const WId windowId) { + // NULL handle is allowed here. + return QLatin1String("0x") + + QString::number(windowId, 16).toUpper().rightJustified(8, u'0'); + } + + static inline /*constexpr*/ QString hwnd2str(HWND hwnd) { + // NULL handle is allowed here. + return hwnd2str(reinterpret_cast<WId>(hwnd)); + } + + static inline bool isWin8OrGreater() { + static const bool result = IsWindows8OrGreater_Real(); + return result; + } + + static inline bool isWin8Point1OrGreater() { + static const bool result = IsWindows8Point1OrGreater_Real(); + return result; + } + + static inline bool isWin10OrGreater() { + static const bool result = IsWindows10OrGreater_Real(); + return result; + } + + static inline bool isWin11OrGreater() { + static const bool result = IsWindows11OrGreater_Real(); + return result; + } + + static inline bool isWin1122H2OrGreater() { + static const bool result = IsWindows1122H2OrGreater_Real(); + return result; + } + + static inline bool isDwmCompositionEnabled() { + if (isWin8OrGreater()) { + return true; + } + const DynamicApis &apis = DynamicApis::instance(); + if (!apis.pDwmIsCompositionEnabled) { + return false; + } + BOOL enabled = FALSE; + return SUCCEEDED(apis.pDwmIsCompositionEnabled(&enabled)) && enabled; + } + + static inline bool isWindowFrameBorderColorized() { + const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); + if (!registry.isValid()) { + return false; + } + const auto value = registry.dwordValue(L"ColorPrevalence"); + if (!value.second) { + return false; + } + return value.first; + } + + static inline bool isDarkThemeActive() { +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + return QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark; +#else + const QWinRegistryKey registry( + HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"); + if (!registry.isValid()) { + return false; + } + const auto value = registry.dwordValue(L"AppsUseLightTheme"); + if (!value.second) { + return false; + } + return !value.first; +#endif + } + + static inline bool isDarkWindowFrameEnabled(HWND hwnd) { + BOOL enabled = FALSE; + const DynamicApis &apis = DynamicApis::instance(); + if (SUCCEEDED(apis.pDwmGetWindowAttribute(hwnd, _DWMWA_USE_IMMERSIVE_DARK_MODE, &enabled, + sizeof(enabled)))) { + return enabled; + } else if (SUCCEEDED(apis.pDwmGetWindowAttribute(hwnd, + _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, + &enabled, sizeof(enabled)))) { + return enabled; + } else { + return false; + } + } + + static inline QColor getAccentColor() { +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) + return QGuiApplication::palette().color(QPalette::Accent); +#else + const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)"); + if (!registry.isValid()) { + return {}; + } + const auto value = registry.dwordValue(L"AccentColor"); + if (!value.second) { + return {}; + } + // The retrieved value is in the #AABBGGRR format, we need to + // convert it to the #AARRGGBB format which Qt expects. + const QColor abgr = QColor::fromRgba(value.first); + if (!abgr.isValid()) { + return {}; + } + return QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha()); +#endif + } + +} + +#endif // QWKWINDOWSEXTRA_P_H -- Gitblit v1.9.1