win: add support for mica alt and other tweaks

Add some more comments to the windows header.
Remove the usages of UseRoundWindowCorner.

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-11-16 14:10:49 +08:00
parent b09acecac6
commit 3791802d3b
16 changed files with 63 additions and 58 deletions

View File

@ -47,7 +47,6 @@ int main(int argc, char *argv[])
// a QGuiApplication instance.
FramelessHelper::Core::setApplicationOSThemeAware();
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);

View File

@ -47,7 +47,6 @@ int main(int argc, char *argv[])
// a QGuiApplication instance.
FramelessHelper::Core::setApplicationOSThemeAware();
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);

View File

@ -84,7 +84,6 @@ int main(int argc, char *argv[])
// a QGuiApplication instance.
FramelessHelper::Core::setApplicationOSThemeAware();
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);

View File

@ -59,7 +59,6 @@ int main(int argc, char *argv[])
// a QGuiApplication instance.
FramelessHelper::Core::setApplicationOSThemeAware();
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);

View File

@ -47,7 +47,6 @@ int main(int argc, char *argv[])
// a QGuiApplication instance.
FramelessHelper::Core::setApplicationOSThemeAware();
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);

View File

@ -302,12 +302,12 @@ using _DPI_AWARENESS = enum _DPI_AWARENESS
using _DWMWINDOWATTRIBUTE = enum _DWMWINDOWATTRIBUTE
{
_DWMWA_USE_HOSTBACKDROPBRUSH = 17, // [set] BOOL, Allows the use of host backdrop brushes for the window.
_DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, // Undocumented
_DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, // Undocumented, the same with DWMWA_USE_IMMERSIVE_DARK_MODE, but available on systems before Win10 20H1.
_DWMWA_USE_IMMERSIVE_DARK_MODE = 20, // [set] BOOL, Allows a window to either use the accent color, or dark, according to the user Color Mode preferences.
_DWMWA_WINDOW_CORNER_PREFERENCE = 33, // [set] WINDOW_CORNER_PREFERENCE, Controls the policy that rounds top-level window corners
_DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37, // [get] UINT, width of the visible border around a thick frame window
_DWMWA_SYSTEMBACKDROP_TYPE = 38, // [get, set] SYSTEMBACKDROP_TYPE, Controls the system-drawn backdrop material of a window, including behind the non-client area.
_DWMWA_MICA_EFFECT = 1029 // Undocumented
_DWMWA_MICA_EFFECT = 1029 // Undocumented, use this value to enable Mica material on Win11 21H2. You should use DWMWA_SYSTEMBACKDROP_TYPE instead on Win11 22H2 and newer.
};
using _DWM_WINDOW_CORNER_PREFERENCE = enum _DWM_WINDOW_CORNER_PREFERENCE
@ -410,10 +410,10 @@ using IMMERSIVE_HC_CACHE_MODE = enum IMMERSIVE_HC_CACHE_MODE
using PREFERRED_APP_MODE = enum PREFERRED_APP_MODE
{
PAM_DEFAULT = 0, // Use default behavior.
PAM_AUTO = 1, // Let system decide.
PAM_DARK = 2, // Force dark mode.
PAM_LIGHT = 3, // Force light mode.
PAM_DEFAULT = 0, // Default behavior on systems before Win10 1809. It indicates the application doesn't support dark mode at all.
PAM_AUTO = 1, // Available since Win10 1809, let system decide whether to enable dark mode or not.
PAM_DARK = 2, // Available since Win10 1903, force dark mode regardless of the system theme.
PAM_LIGHT = 3, // Available since Win10 1903, force light mode regardless of the system theme.
PAM_MAX = 4
};

View File

@ -347,7 +347,8 @@ enum class BlurMode
Default = 1, // Use platform default blur mode
Windows_Aero = 2, // Windows only, use the traditional DWM blur
Windows_Acrylic = 3, // Windows only, use the Acrylic blur
Windows_Mica = 4 // Windows only, use the Mica material
Windows_Mica = 4, // Windows only, use the Mica material
Windows_MicaAlt = 5 // Windows only, use the Mica Alt material
};
Q_ENUM_NS(BlurMode)
@ -379,7 +380,7 @@ enum class RegistryRootKey
Q_ENUM_NS(RegistryRootKey)
#endif // Q_OS_WINDOWS
enum class WindowEdge
enum class WindowEdge : quint32
{
Left = 0x00000000,
Top = 0x00000001,
@ -404,6 +405,14 @@ enum class DpiAwareness
Q_ENUM_NS(DpiAwareness)
#endif // Q_OS_WINDOWS
enum class WindowCornerStyle
{
Default = 0,
Square = 1,
Round = 2
};
Q_ENUM_NS(WindowCornerStyle)
struct VersionNumber
{
int major = 0;

View File

@ -109,7 +109,7 @@ FRAMELESSHELPER_CORE_API void setAeroSnappingEnabled(const WId windowId, const b
FRAMELESSHELPER_CORE_API void tryToEnableHighestDpiAwarenessLevel();
FRAMELESSHELPER_CORE_API void updateGlobalWin32ControlsTheme(const WId windowId, const bool dark);
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_windows();
FRAMELESSHELPER_CORE_API void forceSquareCornersForWindow(const WId windowId, const bool force);
FRAMELESSHELPER_CORE_API void setCornerStyleForWindow(const WId windowId, const Global::WindowCornerStyle style);
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getDwmAccentColor();
FRAMELESSHELPER_CORE_API void hideOriginalTitleBarElements
(const WId windowId, const bool disable = true);

View File

@ -186,10 +186,11 @@ public:
FRAMELESSHELPER_QUICK_ENUM_VALUE(BlurMode, Windows_Aero)
FRAMELESSHELPER_QUICK_ENUM_VALUE(BlurMode, Windows_Acrylic)
FRAMELESSHELPER_QUICK_ENUM_VALUE(BlurMode, Windows_Mica)
FRAMELESSHELPER_QUICK_ENUM_VALUE(BlurMode, Windows_MicaAlt)
};
Q_ENUM(BlurMode)
enum class WindowEdge
enum class WindowEdge : quint32
{
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Left)
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Top)
@ -199,6 +200,14 @@ public:
Q_ENUM(WindowEdge)
Q_DECLARE_FLAGS(WindowEdges, WindowEdge)
Q_FLAG(WindowEdges)
enum class WindowCornerStyle
{
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowCornerStyle, Default)
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowCornerStyle, Square)
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowCornerStyle, Round)
};
Q_ENUM(WindowCornerStyle)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QuickGlobal::WindowEdges)

View File

@ -90,8 +90,7 @@ void FramelessHelperQt::addWindow(const SystemParameters &params)
g_qtHelper()->mutex.unlock();
const bool shouldApplyFramelessFlag = [&params]() -> bool {
#ifdef Q_OS_MACOS
if (FramelessConfig::instance()->isSet(Option::WindowUseRoundCorners)
&& (params.getCurrentApplicationType() == ApplicationType::Quick)) {
if (params.getCurrentApplicationType() == ApplicationType::Quick) {
return false;
}
#else

View File

@ -559,13 +559,9 @@ void FramelessHelperWin::addWindow(const SystemParameters &params)
}
Utils::refreshWin32ThemeResources(windowId, dark);
if (WindowsVersionHelper::isWin11OrGreater()) {
const FramelessConfig * const config = FramelessConfig::instance();
// Set the frame corner style, only Win11 provides official public API to do it.
// On Win7~Win10, you'll need to use SetWindowRgn(), which will break the frame shadow.
Utils::forceSquareCornersForWindow(windowId, !config->isSet(Option::WindowUseRoundCorners));
// The fallback title bar window is only used to activate the Snap Layout feature
// introduced in Windows 11, so it's not necessary to create it on systems below Win11.
if (!config->isSet(Option::DisableWindowsSnapLayout)) {
if (!FramelessConfig::instance()->isSet(Option::DisableWindowsSnapLayout)) {
if (!createFallbackTitleBarWindow(windowId, data.params.isWindowFixedSize())) {
WARNING << "Failed to create the fallback title bar window.";
}

View File

@ -202,6 +202,7 @@ void initialize()
# ifdef Q_OS_WINDOWS
qRegisterMetaType<DpiAwareness>();
# endif
qRegisterMetaType<WindowCornerStyle>();
qRegisterMetaType<VersionNumber>();
qRegisterMetaType<SystemParameters>();
qRegisterMetaType<VersionInfo>();

View File

@ -2214,7 +2214,7 @@ bool Utils::shouldAppsUseDarkMode_windows()
return resultFromRegistry();
}
void Utils::forceSquareCornersForWindow(const WId windowId, const bool force)
void Utils::setCornerStyleForWindow(const WId windowId, const WindowCornerStyle style)
{
Q_ASSERT(windowId);
if (!windowId) {
@ -2228,8 +2228,20 @@ void Utils::forceSquareCornersForWindow(const WId windowId, const bool force)
return;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const _DWM_WINDOW_CORNER_PREFERENCE wcp = (force ? _DWMWCP_DONOTROUND : _DWMWCP_ROUND);
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd, _DWMWA_WINDOW_CORNER_PREFERENCE, &wcp, sizeof(wcp));
const auto wcp = [style]() -> _DWM_WINDOW_CORNER_PREFERENCE {
switch (style) {
case WindowCornerStyle::Default:
return _DWMWCP_DEFAULT;
case WindowCornerStyle::Square:
return _DWMWCP_DONOTROUND;
case WindowCornerStyle::Round:
return _DWMWCP_ROUND;
}
Q_ASSERT(false);
return _DWMWCP_DEFAULT;
}();
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute,
hwnd, _DWMWA_WINDOW_CORNER_PREFERENCE, &wcp, sizeof(wcp));
if (FAILED(hr)) {
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
}
@ -2256,11 +2268,13 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
g_micaData()->mutex.unlock();
updateWindowFrameMargins(windowId, false);
};
const BlurMode blurMode = [mode]() -> BlurMode {
const bool preferMicaAlt = (qEnvironmentVariableIntValue("FRAMELESSHELPER_PREFER_MICA_ALT") != 0);
const BlurMode blurMode = [mode, preferMicaAlt]() -> BlurMode {
if ((mode == BlurMode::Disable) || (mode == BlurMode::Windows_Aero)) {
return mode;
}
if ((mode == BlurMode::Windows_Mica) && !WindowsVersionHelper::isWin11OrGreater()) {
if (((mode == BlurMode::Windows_Mica) || (mode == BlurMode::Windows_MicaAlt))
&& !WindowsVersionHelper::isWin11OrGreater()) {
WARNING << "The Mica material is not supported on your system, fallback to the Acrylic blur instead...";
if (WindowsVersionHelper::isWin10OrGreater()) {
return BlurMode::Windows_Acrylic;
@ -2274,7 +2288,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
}
if (mode == BlurMode::Default) {
if (WindowsVersionHelper::isWin11OrGreater()) {
return BlurMode::Windows_Mica;
return (preferMicaAlt ? BlurMode::Windows_MicaAlt : BlurMode::Windows_Mica);
}
if (WindowsVersionHelper::isWin10OrGreater()) {
return BlurMode::Windows_Acrylic;
@ -2321,7 +2335,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
}
return result;
} else {
if (blurMode == BlurMode::Windows_Mica) {
if ((blurMode == BlurMode::Windows_Mica) || (blurMode == BlurMode::Windows_MicaAlt)) {
g_micaData()->mutex.lock();
if (!g_micaData()->windowIds.contains(windowId)) {
g_micaData()->windowIds.append(windowId);
@ -2347,8 +2361,8 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
if (SUCCEEDED(hr)) {
if (WindowsVersionHelper::isWin1122H2OrGreater()) {
const auto dwmsbt = (
qEnvironmentVariableIntValue("FRAMELESSHELPER_USE_MICA_ALT")
? _DWMSBT_TABBEDWINDOW : _DWMSBT_MAINWINDOW);
((blurMode == BlurMode::Windows_MicaAlt) || preferMicaAlt)
? _DWMSBT_TABBEDWINDOW : _DWMSBT_MAINWINDOW);
hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd,
_DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt));
if (SUCCEEDED(hr)) {

View File

@ -90,6 +90,7 @@ void initialize()
qRegisterMetaType<QuickGlobal::BlurMode>();
qRegisterMetaType<QuickGlobal::WindowEdge>();
qRegisterMetaType<QuickGlobal::WindowEdges>();
qRegisterMetaType<QuickGlobal::WindowCornerStyle>();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
qRegisterMetaType<QuickGlobal>();

View File

@ -645,23 +645,14 @@ bool FramelessQuickHelperPrivate::eventFilter(QObject *object, QEvent *event)
return QObject::eventFilter(object, event);
}
const auto window = qobject_cast<QQuickWindow *>(object);
const WId windowId = window->winId();
const bool roundCorner = FramelessConfig::instance()->isSet(Option::WindowUseRoundCorners);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
if (Utils::windowStatesToWindowState(window->windowStates()) == Qt::WindowFullScreen) {
if (Utils::windowStatesToWindowState(window->windowStates()) != Qt::WindowFullScreen) {
#else
if (window->windowState() == Qt::WindowFullScreen) {
if (window->windowState() != Qt::WindowFullScreen) {
#endif
if (WindowsVersionHelper::isWin11OrGreater() && roundCorner) {
Utils::forceSquareCornersForWindow(windowId, true);
}
} else {
const auto changeEvent = static_cast<QWindowStateChangeEvent *>(event);
if (Utils::windowStatesToWindowState(changeEvent->oldState()) == Qt::WindowFullScreen) {
Utils::maybeFixupQtInternals(windowId);
if (WindowsVersionHelper::isWin11OrGreater() && roundCorner) {
Utils::forceSquareCornersForWindow(windowId, false);
}
Utils::maybeFixupQtInternals(window->winId());
}
}
#endif

View File

@ -196,21 +196,11 @@ void WidgetsSharedHelper::changeEventHandler(QEvent *event)
}
}
#ifdef Q_OS_WINDOWS
if (FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation)) {
return;
}
const WId windowId = m_targetWidget->winId();
const bool roundCorner = FramelessConfig::instance()->isSet(Option::WindowUseRoundCorners);
if (Utils::windowStatesToWindowState(m_targetWidget->windowState()) == Qt::WindowFullScreen) {
if (WindowsVersionHelper::isWin11OrGreater() && roundCorner) {
Utils::forceSquareCornersForWindow(windowId, true);
}
} else {
const auto changeEvent = static_cast<QWindowStateChangeEvent *>(event);
if (Utils::windowStatesToWindowState(changeEvent->oldState()) == Qt::WindowFullScreen) {
Utils::maybeFixupQtInternals(windowId);
if (WindowsVersionHelper::isWin11OrGreater() && roundCorner) {
Utils::forceSquareCornersForWindow(windowId, false);
if (!FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation)) {
if (Utils::windowStatesToWindowState(m_targetWidget->windowState()) != Qt::WindowFullScreen) {
const auto changeEvent = static_cast<QWindowStateChangeEvent *>(event);
if (Utils::windowStatesToWindowState(changeEvent->oldState()) == Qt::WindowFullScreen) {
Utils::maybeFixupQtInternals(m_targetWidget->winId());
}
}
}