diff --git a/Common/Common.cpp b/Common/Common.cpp index 2b6bfa1..ddd77fb 100644 --- a/Common/Common.cpp +++ b/Common/Common.cpp @@ -1,4 +1,4 @@ -/** +/** * FileName: Common.cpp * * Copyright (C) 2024 Maplespe @@ -82,6 +82,8 @@ namespace MDWMBlurGlass cfgData.reflection = Utils::GetIniString(path, L"config", L"reflection") == L"true"; cfgData.oldBtnHeight = Utils::GetIniString(path, L"config", L"oldBtnHeight") == L"true"; cfgData.customAmount = Utils::GetIniString(path, L"config", L"customAmount") == L"true"; + // newly added params since 2.1.0 + cfgData.overrideAccent = Utils::GetIniString(path, L"config", L"overrideAccent") == L"true"; auto ret = Utils::GetIniString(path, L"config", L"extendRound"); @@ -148,31 +150,24 @@ namespace MDWMBlurGlass if (!ret.empty()) cfgData.blurmethod = (blurMethod)std::clamp(_wtoi(ret.data()), 0, 2); - // new - begin - - ret = Utils::GetIniString(path, L"aero", L"PrimaryBalance"); + // newly added params since 2.1.0 + ret = Utils::GetIniString(path, L"config", L"glassIntensity"); if (!ret.empty()) - cfgData.PrimaryBalance = (float)std::clamp(_wtof(ret.data()), 0.0, 1.0); - - ret = Utils::GetIniString(path, L"aero", L"Active_SecondaryBalance"); + cfgData.glassIntensity = (float)std::clamp(_wtof(ret.data()), 0.0, 1.0); + ret = Utils::GetIniString(path, L"config.aero", L"activeColorBalance"); if (!ret.empty()) - cfgData.Active_SecondaryBalance = (float)std::clamp(_wtof(ret.data()), 0.0, 1.0); - - ret = Utils::GetIniString(path, L"aero", L"Inactive_SecondaryBalance"); + cfgData.activeColorBalance = (float)std::clamp(_wtof(ret.data()), 0.0, 1.0); + ret = Utils::GetIniString(path, L"config.aero", L"inactiveColorBalance"); if (!ret.empty()) - cfgData.Inactive_SecondaryBalance = (float)std::clamp(_wtof(ret.data()), 0.0, 1.0); - + cfgData.inactiveColorBalance = (float)std::clamp(_wtof(ret.data()), 0.0, 1.0); - ret = Utils::GetIniString(path, L"aero", L"Active_BlurBalance"); + ret = Utils::GetIniString(path, L"config.aero", L"activeBlurBalance"); if (!ret.empty()) - cfgData.Active_BlurBalance = (float)std::clamp(_wtof(ret.data()), -1.0, 1.0); - - ret = Utils::GetIniString(path, L"aero", L"Inactive_BlurBalance"); + cfgData.activeBlurBalance = (float)std::clamp(_wtof(ret.data()), -1.0, 1.0); + ret = Utils::GetIniString(path, L"config.aero", L"inactiveBlurBalance"); if (!ret.empty()) - cfgData.Inactive_BlurBalance = (float)std::clamp(_wtof(ret.data()), -1.0, 1.0); - - - // new - end + cfgData.inactiveBlurBalance = (float)std::clamp(_wtof(ret.data()), -1.0, 1.0); + // ret = Utils::GetIniString(path, L"config", L"effectType"); if (!ret.empty()) @@ -181,6 +176,13 @@ namespace MDWMBlurGlass if (cfgData.blurmethod != blurMethod::CustomBlur && cfgData.effectType > effectType::Acrylic) cfgData.effectType = effectType::Acrylic; } + + // newly added params since 2.1.0 + ret = Utils::GetIniString(path, L"config", L"crossfadeTime"); + if (!ret.empty()) + { + cfgData.crossfadeTime = (UINT)_wtoll(ret.data()); + } return cfgData; } @@ -191,9 +193,21 @@ namespace MDWMBlurGlass Utils::SetIniString(path, L"config", L"reflection", cfg.reflection ? L"true" : L"false"); Utils::SetIniString(path, L"config", L"oldBtnHeight", cfg.oldBtnHeight ? L"true" : L"false"); Utils::SetIniString(path, L"config", L"customAmount", cfg.customAmount ? L"true" : L"false"); + + // newly added params since 2.1.0 + Utils::SetIniString(path, L"config", L"overrideAccent", cfg.overrideAccent ? L"true" : L"false"); + Utils::SetIniString(path, L"config", L"blurAmount", std::to_wstring(cfg.blurAmount)); Utils::SetIniString(path, L"config", L"customBlurAmount", std::to_wstring(cfg.customBlurAmount)); Utils::SetIniString(path, L"config", L"luminosityOpacity", std::to_wstring(cfg.luminosityOpacity)); + + // newly added params since 2.1.0 + Utils::SetIniString(path, L"config", L"glassIntensity", std::to_wstring(cfg.glassIntensity)); + Utils::SetIniString(path, L"config.aero", L"activeColorBalance", std::to_wstring(cfg.activeColorBalance)); + Utils::SetIniString(path, L"config.aero", L"inactiveColorBalance", std::to_wstring(cfg.inactiveColorBalance)); + Utils::SetIniString(path, L"config.aero", L"activeBlurBalance", std::to_wstring(cfg.activeBlurBalance)); + Utils::SetIniString(path, L"config.aero", L"inactiveBlurBalance", std::to_wstring(cfg.inactiveBlurBalance)); + Utils::SetIniString(path, L"config", L"activeTextColor", std::to_wstring(cfg.activeTextColor)); Utils::SetIniString(path, L"config", L"inactiveTextColor", std::to_wstring(cfg.inactiveTextColor)); Utils::SetIniString(path, L"config", L"activeTextColorDark", std::to_wstring(cfg.activeTextColorDark)); @@ -205,6 +219,7 @@ namespace MDWMBlurGlass Utils::SetIniString(path, L"config", L"blurMethod", std::to_wstring((int)cfg.blurmethod)); Utils::SetIniString(path, L"config", L"effectType", std::to_wstring((int)cfg.effectType)); - // not on the gui... not sure if i should put the new entries here! + // newly added params since 2.1.0 + Utils::SetIniString(path, L"config", L"crossfadeTime", std::to_wstring(cfg.crossfadeTime)); } } diff --git a/Common/Common.h b/Common/Common.h index f356530..ed0f802 100644 --- a/Common/Common.h +++ b/Common/Common.h @@ -33,6 +33,7 @@ namespace MDWMBlurGlass enum class effectType { + None=-1, Blur, Aero, Acrylic, @@ -46,19 +47,22 @@ namespace MDWMBlurGlass bool reflection = false; bool oldBtnHeight = false; bool customAmount = false; + // newly added params since 2.1.0 + bool overrideAccent = false; int extendRound = 10; float blurAmount = 20.f; float customBlurAmount = 20.f; float luminosityOpacity = 0.65f; + // newly added params since 2.1.0 + float glassIntensity = 1.f; // these settings are optimal for the default Sky color from Windows 7 - - float PrimaryBalance = 0.08f; - float Active_SecondaryBalance = 0.43f; - float Inactive_SecondaryBalance = 0.43f; - float Active_BlurBalance = -0.125f; - float Inactive_BlurBalance = 0.365f; + // newly added params since 2.1.0 + float activeColorBalance = 0.08f; + float inactiveColorBalance = 0.032f; + float activeBlurBalance = -0.125f; + float inactiveBlurBalance = 0.365f; COLORREF activeTextColor = 0xFF000000; COLORREF inactiveTextColor = 0xFFB4B4B4; @@ -73,6 +77,8 @@ namespace MDWMBlurGlass blurMethod blurmethod = blurMethod::CustomBlur; effectType effectType = effectType::Blur; + // newly added params since 2.1.0 + UINT crossfadeTime = 87; bool isDefault() { diff --git a/Common/VersionHelper.cpp b/Common/VersionHelper.cpp index 1902d58..0a618ae 100644 --- a/Common/VersionHelper.cpp +++ b/Common/VersionHelper.cpp @@ -1,4 +1,4 @@ -/** +/** * FileName: VersionHelper.cpp * * Copyright (C) 2024 Maplespe diff --git a/DWMBlurGlass/MHostHelper.cpp b/DWMBlurGlass/MHostHelper.cpp index 3b8ddf6..3e46be9 100644 --- a/DWMBlurGlass/MHostHelper.cpp +++ b/DWMBlurGlass/MHostHelper.cpp @@ -144,8 +144,9 @@ namespace MDWMBlurGlass const bool ret = Inject(GetProcessId(L"dwm.exe"), Utils::GetCurrentDir() + L"\\DWMBlurGlassExt.dll", err); if(ret) { - BOOL enable = TRUE; - SystemParametersInfoW(SPI_SETGRADIENTCAPTIONS, 0, &enable, SPIF_SENDCHANGE); + /*BOOL enable = TRUE; + SystemParametersInfoW(SPI_SETGRADIENTCAPTIONS, 0, &enable, SPIF_SENDCHANGE);*/ + PostMessageW(FindWindowW(L"Dwm", nullptr), WM_THEMECHANGED, 0, 0); } return ret; } diff --git a/DWMBlurGlass/MainWindow.h b/DWMBlurGlass/MainWindow.h index 1ffdf49..97292c8 100644 --- a/DWMBlurGlass/MainWindow.h +++ b/DWMBlurGlass/MainWindow.h @@ -21,7 +21,7 @@ namespace MDWMBlurGlass { - inline const std::wstring g_vernum = L"2.0.1"; + inline const std::wstring g_vernum = L"2.1.0"; Mui::_m_result MainWindow_SrcEventProc(Mui::MWindowCtx*, const Mui::MWndDefEventSource&, Mui::MEventCodeEnum, Mui::_m_param); diff --git a/DWMBlurGlass/Page/MainPage.cpp b/DWMBlurGlass/Page/MainPage.cpp index b71436e..9e772b4 100644 --- a/DWMBlurGlass/Page/MainPage.cpp +++ b/DWMBlurGlass/Page/MainPage.cpp @@ -263,13 +263,13 @@ namespace MDWMBlurGlass MessageBoxW(hWnd, (m_ui->GetStringValue(L"loadfail") + err).c_str(), L"Error", MB_ICONERROR); return false; } - if (symbolState) - RefreshSysConfig(); - MessageBoxW(hWnd, + // if (symbolState) + //RefreshSysConfig(); + /* MessageBoxW(hWnd, m_ui->GetStringValue(symbolState ? L"installsucs" : L"installsucs1").c_str(), m_ui->GetStringValue(L"install").c_str(), MB_ICONINFORMATION - ); + );*/ } else MessageBoxW(hWnd, @@ -285,13 +285,13 @@ namespace MDWMBlurGlass ShutdownDWMExtension(errinfo); if (DeleteScheduledTasks(errinfo)) { - RefreshSysConfig(); + //RefreshSysConfig(); - MessageBoxW(hWnd, + /*MessageBoxW(hWnd, m_ui->GetStringValue(L"uninstallsucs").c_str(), m_ui->GetStringValue(L"uninstall").c_str(), MB_ICONINFORMATION - ); + );*/ } else MessageBoxW(hWnd, @@ -673,10 +673,12 @@ namespace MDWMBlurGlass void MainWindowPage::RefreshSysConfig() { - BOOL enable = TRUE; + PostMessageW(FindWindowW(L"Dwm", nullptr), WM_THEMECHANGED, 0, 0); + InvalidateRect(nullptr, nullptr, FALSE); + /*BOOL enable = TRUE; SystemParametersInfoW(SPI_SETGRADIENTCAPTIONS, 0, &enable, SPIF_SENDCHANGE); SendNotifyMessageW(HWND_BROADCAST, WM_DWMCOLORIZATIONCOLORCHANGED, m_cfgData.activeBlendColor, 1); - BroadcastSystemMessageW(BSF_POSTMESSAGE, nullptr, WM_THEMECHANGED, 0, 0); + BroadcastSystemMessageW(BSF_POSTMESSAGE, nullptr, WM_THEMECHANGED, 0, 0);*/ } void MainWindowPage::RefreshBlurPreview() diff --git a/DWMBlurGlass/Resource.rc b/DWMBlurGlass/Resource.rc index 35c85bd..8236afa 100644 Binary files a/DWMBlurGlass/Resource.rc and b/DWMBlurGlass/Resource.rc differ diff --git a/DWMBlurGlass/pugixml/pugiconfig.hpp b/DWMBlurGlass/pugixml/pugiconfig.hpp index c80a365..df53ff1 100644 --- a/DWMBlurGlass/pugixml/pugiconfig.hpp +++ b/DWMBlurGlass/pugixml/pugiconfig.hpp @@ -1,4 +1,4 @@ -/** +/** * pugixml parser - version 1.12 * -------------------------------------------------------- * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) diff --git a/DWMBlurGlass/pugixml/pugixml.cpp b/DWMBlurGlass/pugixml/pugixml.cpp index 60b55da..9aeec7b 100644 --- a/DWMBlurGlass/pugixml/pugixml.cpp +++ b/DWMBlurGlass/pugixml/pugixml.cpp @@ -1,4 +1,4 @@ -/** +/** * pugixml parser - version 1.12 * -------------------------------------------------------- * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) diff --git a/DWMBlurGlass/pugixml/pugixml.hpp b/DWMBlurGlass/pugixml/pugixml.hpp index 5a8496d..dec4d41 100644 --- a/DWMBlurGlass/pugixml/pugixml.hpp +++ b/DWMBlurGlass/pugixml/pugixml.hpp @@ -1,4 +1,4 @@ -/** +/** * pugixml parser - version 1.12 * -------------------------------------------------------- * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) diff --git a/DWMBlurGlassExt/Backdrops/AcrylicBackdrop.hpp b/DWMBlurGlassExt/Backdrops/AcrylicBackdrop.hpp new file mode 100644 index 0000000..c4fa5d7 --- /dev/null +++ b/DWMBlurGlassExt/Backdrops/AcrylicBackdrop.hpp @@ -0,0 +1,530 @@ +#pragma once +#include "DCompBackdrop.hpp" +#include "../Effects/CrossFadeEffect.hpp" +#include "../Effects/GaussianBlurEffect.hpp" +#include "../Effects/ColorSourceEffect.hpp" +#include "../Effects/OpacityEffect.hpp" +#include "../Effects/BorderEffect.hpp" +#include "../Effects/BlendEffect.hpp" +#include + +namespace MDWMBlurGlassExt +{ + struct CAcrylicResources : CDCompResources + { + float lightMode_Active_TintOpacity{}; + float lightMode_Inactive_TintOpacity{}; + float darkMode_Active_TintOpacity{}; + float darkMode_Inactive_TintOpacity{}; + std::optional lightMode_Active_LuminosityOpacity{}; + std::optional lightMode_Inactive_LuminosityOpacity{}; + std::optional darkMode_Active_LuminosityOpacity{}; + std::optional darkMode_Inactive_LuminosityOpacity{}; + float blurAmount{ 30.f }; + bool hostBackdrop{ false }; + + static double GetTintOpacityModifier(winrt::Windows::UI::Color tintColor) + { + // This method supresses the maximum allowable tint opacity depending on the luminosity and saturation of a color by + // compressing the range of allowable values - for example, a user-defined value of 100% will be mapped to 45% for pure + // white (100% luminosity), 85% for pure black (0% luminosity), and 90% for pure gray (50% luminosity). The intensity of + // the effect increases linearly as luminosity deviates from 50%. After this effect is calculated, we cancel it out + // linearly as saturation increases from zero. + + constexpr double midPoint{ 0.50 }; // Mid point of HsvV range that these calculations are based on. This is here for easy tuning. + + constexpr double whiteMaxOpacity{ 0.45 }; // 100% luminosity + constexpr double midPointMaxOpacity{ 0.90 }; // 50% luminosity + constexpr double blackMaxOpacity{ 0.85 }; // 0% luminosity + + const auto rgb{ RgbFromColor(tintColor) }; + const auto hsv{ RgbToHsv(rgb) }; + + double opacityModifier{ midPointMaxOpacity }; + + if (hsv.v != midPoint) + { + // Determine maximum suppression amount + double lowestMaxOpacity = midPointMaxOpacity; + double maxDeviation = midPoint; + + if (hsv.v > midPoint) + { + lowestMaxOpacity = whiteMaxOpacity; // At white (100% hsvV) + maxDeviation = 1 - maxDeviation; + } + else if (hsv.v < midPoint) + { + lowestMaxOpacity = blackMaxOpacity; // At black (0% hsvV) + } + + double maxOpacitySuppression = midPointMaxOpacity - lowestMaxOpacity; + + // Determine normalized deviation from the midpoint + const double deviation = std::abs(hsv.v - midPoint); + const double normalizedDeviation = deviation / maxDeviation; + + // If we have saturation, reduce opacity suppression to allow that color to come through more + if (hsv.s > 0) + { + // Dampen opacity suppression based on how much saturation there is + #pragma push_macro("max") + #undef max + maxOpacitySuppression *= std::max(1 - (hsv.s * 2), 0.0); + #pragma pop_macro("max") + } + + const double opacitySuppression = maxOpacitySuppression * normalizedDeviation; + + opacityModifier = midPointMaxOpacity - opacitySuppression; + } + + return opacityModifier; + } + static winrt::Windows::UI::Color GetEffectiveTintColor(winrt::Windows::UI::Color tintColor, float tintOpacity, std::optional luminosityOpacity) + { + const double tintOpacityModifier{ GetTintOpacityModifier(tintColor) }; + if (luminosityOpacity) + { + tintColor.A = static_cast(round(tintColor.A * tintOpacity)); + } + else + { + const double tintOpacityModifier{ GetTintOpacityModifier(tintColor) }; + tintColor.A = static_cast(round(tintColor.A * tintOpacity * tintOpacityModifier)); + } + + return tintColor; + } + // The tintColor passed into this method should be the original, unmodified color created using user values for TintColor + TintOpacity + static winrt::Windows::UI::Color GetLuminosityColor(winrt::Windows::UI::Color tintColor, std::optional luminosityOpacity) + { + const Rgb rgbTintColor = RgbFromColor(tintColor); + + // If luminosity opacity is specified, just use the values as is + if (luminosityOpacity) + { + return ColorFromRgba(rgbTintColor, std::clamp(luminosityOpacity.value(), 0.0, 1.0)); + } + else + { + // To create the Luminosity blend input color without luminosity opacity, + // we're taking the TintColor input, converting to HSV, and clamping the V between these values + const double minHsvV = 0.125; + const double maxHsvV = 0.965; + + const Hsv hsvTintColor = RgbToHsv(rgbTintColor); + + const auto clampedHsvV = std::clamp(hsvTintColor.v, minHsvV, maxHsvV); + + const Hsv hsvLuminosityColor = Hsv(hsvTintColor.h, hsvTintColor.s, clampedHsvV); + const Rgb rgbLuminosityColor = HsvToRgb(hsvLuminosityColor); + + // Now figure out luminosity opacity + // Map original *tint* opacity to this range + const double minLuminosityOpacity = 0.15; + const double maxLuminosityOpacity = 1.03; + + const double luminosityOpacityRangeMax = maxLuminosityOpacity - minLuminosityOpacity; + const double mappedTintOpacity = ((tintColor.A / 255.0) * luminosityOpacityRangeMax) + minLuminosityOpacity; + + // Finally, combine the luminosity opacity and the HsvV-clamped tint color + #pragma push_macro("min") + #undef min + return ColorFromRgba(rgbLuminosityColor, std::min(mappedTintOpacity, 1.0)); + #pragma pop_macro("min") + } + + } + static winrt::Windows::UI::Color GetEffectiveLuminosityColor(winrt::Windows::UI::Color tintColor, float tintOpacity, std::optional luminosityOpacity) + { + // Purposely leaving out tint opacity modifier here because GetLuminosityColor needs the *original* tint opacity set by the user. + tintColor.A = static_cast(round(tintColor.A * tintOpacity)); + + return GetLuminosityColor(tintColor, luminosityOpacity); + } + + static winrt::Windows::UI::Composition::CompositionBrush CreateBrush( + const winrt::Windows::UI::Composition::Compositor& compositor, + const winrt::Windows::UI::Composition::CompositionSurfaceBrush& noiceBrush, + const winrt::Windows::UI::Color& tintColor, + const winrt::Windows::UI::Color& luminosityColor, + float blurAmount, + bool hostBackdrop + ) try + { + if (tintColor.A == 255) + { + return compositor.CreateColorBrush(tintColor); + } + + auto tintColorEffect{ winrt::make_self() }; + tintColorEffect->SetName(L"TintColor"); + tintColorEffect->SetColor(tintColor); + + auto luminosityColorEffect{ winrt::make_self() }; + luminosityColorEffect->SetName(L"LuminosityColor"); + luminosityColorEffect->SetColor(luminosityColor); + + auto luminosityBlendEffect{ winrt::make_self() }; + // NOTE: There is currently a bug where the names of BlendEffectMode::Luminosity and BlendEffectMode::Color are flipped-> + // This should be changed to Luminosity when/if the bug is fixed-> + luminosityBlendEffect->SetBlendMode(D2D1_BLEND_MODE_COLOR); + if (hostBackdrop) + { + luminosityBlendEffect->SetBackground(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"Backdrop" }); + } + else + { + auto gaussianBlurEffect{ winrt::make_self() }; + gaussianBlurEffect->SetName(L"Blur"); + gaussianBlurEffect->SetBorderMode(D2D1_BORDER_MODE_HARD); + gaussianBlurEffect->SetBlurAmount(blurAmount); + gaussianBlurEffect->SetInput(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"Backdrop" }); + luminosityBlendEffect->SetBackground(*gaussianBlurEffect); + } + luminosityBlendEffect->SetForeground(*luminosityColorEffect); + + auto colorBlendEffect{ winrt::make_self() }; + // NOTE: There is currently a bug where the names of BlendEffectMode::Luminosity and BlendEffectMode::Color are flipped-> + // This should be changed to Color when/if the bug is fixed-> + colorBlendEffect->SetBlendMode(D2D1_BLEND_MODE_LUMINOSITY); + colorBlendEffect->SetBackground(*luminosityBlendEffect); + colorBlendEffect->SetForeground(*tintColorEffect); + + auto noiseBorderEffect{ winrt::make_self() }; + noiseBorderEffect->SetExtendX(D2D1_BORDER_EDGE_MODE_WRAP); + noiseBorderEffect->SetExtendY(D2D1_BORDER_EDGE_MODE_WRAP); + winrt::Windows::UI::Composition::CompositionEffectSourceParameter noiseEffectSourceParameter{ L"Noise" }; + noiseBorderEffect->SetInput(noiseEffectSourceParameter); + + auto noiseOpacityEffect{ winrt::make_self() }; + noiseOpacityEffect->SetName(L"NoiseOpacity"); + noiseOpacityEffect->SetOpacity(0.02f); + noiseOpacityEffect->SetInput(*noiseBorderEffect); + + auto blendEffectOuter{ winrt::make_self() }; + blendEffectOuter->SetBlendMode(D2D1_BLEND_MODE_MULTIPLY); + blendEffectOuter->SetBackground(*colorBlendEffect); + blendEffectOuter->SetForeground(*noiseOpacityEffect); + + auto effectBrush{ compositor.CreateEffectFactory(*blendEffectOuter).CreateBrush() }; + effectBrush.SetSourceParameter(L"Noise", noiceBrush); + if (hostBackdrop) + { + effectBrush.SetSourceParameter(L"Backdrop", compositor.CreateHostBackdropBrush()); + } + else + { + effectBrush.SetSourceParameter(L"Backdrop", compositor.CreateBackdropBrush()); + } + + return effectBrush; + } + catch (...) { return nullptr; } + + static winrt::Windows::UI::Composition::CompositionSurfaceBrush CreateNoiceSurfaceBrush( + const winrt::Windows::UI::Composition::Compositor& compositor, + ID2D1Device* d2dDevice + ) try + { + winrt::Windows::UI::Composition::CompositionGraphicsDevice graphicsDevice{ nullptr }; + THROW_IF_FAILED( + compositor.as()->CreateGraphicsDevice( + d2dDevice, + reinterpret_cast(winrt::put_abi(graphicsDevice)) + ) + ); + auto compositionSurface + { + graphicsDevice.CreateDrawingSurface( + { 256.f, 256.f }, + winrt::Windows::Graphics::DirectX::DirectXPixelFormat::R16G16B16A16Float, + winrt::Windows::Graphics::DirectX::DirectXAlphaMode::Premultiplied + ) + }; + auto noiceBrush{ compositor.CreateSurfaceBrush(compositionSurface) }; + + wil::unique_hmodule wuxcModule{ LoadLibraryExW(L"Windows.UI.Xaml.Controls.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE) }; + THROW_LAST_ERROR_IF_NULL(wuxcModule); + auto resourceHandle{ FindResourceW(wuxcModule.get(), MAKEINTRESOURCE(2000), RT_RCDATA) }; + THROW_LAST_ERROR_IF_NULL(resourceHandle); + auto globalHandle{ LoadResource(wuxcModule.get(), resourceHandle) }; + THROW_LAST_ERROR_IF_NULL(globalHandle); + auto cleanUp = wil::scope_exit([&] + { + if (globalHandle) + { + UnlockResource(globalHandle); + FreeResource(globalHandle); + } + }); + DWORD resourceSize{ SizeofResource(wuxcModule.get(), resourceHandle) }; + THROW_LAST_ERROR_IF(resourceSize == 0); + auto resourceAddress{ reinterpret_cast(LockResource(globalHandle)) }; + winrt::com_ptr stream{ SHCreateMemStream(resourceAddress, resourceSize), winrt::take_ownership_from_abi }; + THROW_LAST_ERROR_IF_NULL(stream); + + winrt::com_ptr wicFactory{ nullptr }; + wicFactory.copy_from(DWM::CDesktopManager::s_pDesktopManagerInstance->GetWICFactory()); + winrt::com_ptr wicDecoder{ nullptr }; + THROW_IF_FAILED(wicFactory->CreateDecoderFromStream(stream.get(), &GUID_VendorMicrosoft, WICDecodeMetadataCacheOnDemand, wicDecoder.put())); + winrt::com_ptr wicFrame{ nullptr }; + THROW_IF_FAILED(wicDecoder->GetFrame(0, wicFrame.put())); + winrt::com_ptr wicConverter{ nullptr }; + THROW_IF_FAILED(wicFactory->CreateFormatConverter(wicConverter.put())); + winrt::com_ptr wicPalette{ nullptr }; + THROW_IF_FAILED( + wicConverter->Initialize( + wicFrame.get(), + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + wicPalette.get(), + 0, WICBitmapPaletteTypeCustom + ) + ); + winrt::com_ptr wicBitmap{ nullptr }; + THROW_IF_FAILED(wicFactory->CreateBitmapFromSource(wicConverter.get(), WICBitmapCreateCacheOption::WICBitmapNoCache, wicBitmap.put())); + + auto drawingSurfaceInterop{ compositionSurface.as() }; + POINT offset = { 0, 0 }; + winrt::com_ptr d2dContext{ nullptr }; + THROW_IF_FAILED( + drawingSurfaceInterop->BeginDraw(nullptr, IID_PPV_ARGS(d2dContext.put()), &offset) + ); + d2dContext->Clear(); + winrt::com_ptr d2dBitmap{ nullptr }; + d2dContext->CreateBitmapFromWicBitmap( + wicBitmap.get(), + D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_NONE, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED) + ), + d2dBitmap.put() + ); + d2dContext->DrawBitmap(d2dBitmap.get()); + THROW_IF_FAILED( + drawingSurfaceInterop->EndDraw() + ); + + return noiceBrush; + } + catch (...) { return nullptr; } + + void STDMETHODCALLTYPE ReloadParameters() + { + crossfadeTime = std::chrono::milliseconds{ g_configData.crossfadeTime }; + + darkMode_Active_Color = MakeWinrtColor(g_configData.activeBlendColorDark); + darkMode_Inactive_Color = MakeWinrtColor(g_configData.inactiveBlendColorDark); + lightMode_Active_Color = MakeWinrtColor(g_configData.activeBlendColor); + lightMode_Inactive_Color = MakeWinrtColor(g_configData.inactiveBlendColor); + + lightMode_Active_TintOpacity = GetFloatAlpha(g_configData.activeBlendColor); + lightMode_Inactive_TintOpacity = GetFloatAlpha(g_configData.inactiveBlendColor); + darkMode_Active_TintOpacity = GetFloatAlpha(g_configData.activeBlendColorDark); + darkMode_Inactive_TintOpacity = GetFloatAlpha(g_configData.inactiveBlendColorDark); + + lightMode_Active_LuminosityOpacity = g_configData.luminosityOpacity; + lightMode_Inactive_LuminosityOpacity = g_configData.luminosityOpacity; + darkMode_Active_LuminosityOpacity = g_configData.luminosityOpacity; + darkMode_Inactive_LuminosityOpacity = g_configData.luminosityOpacity; + + blurAmount = g_configData.customBlurAmount; + } + winrt::Windows::UI::Composition::CompositionBrush STDMETHODCALLTYPE GetBrush(bool useDarkMode, bool windowActivated) override try + { + auto is_device_valid = [&]() + { + if (!interopDCompDevice) return false; + + BOOL valid{ FALSE }; + THROW_IF_FAILED( + interopDCompDevice.as()->CheckDeviceState( + &valid + ) + ); + + return valid == TRUE; + }; + if (!is_device_valid()) + { + interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + ReloadParameters(); + auto compositor{ interopDCompDevice.as() }; + auto noiceBrush{ CreateNoiceSurfaceBrush(compositor, DWM::CDesktopManager::s_pDesktopManagerInstance->GetD2DDevice()) }; + + lightMode_Active_Brush = CreateBrush( + compositor, + noiceBrush, + GetEffectiveTintColor(lightMode_Active_Color, lightMode_Active_TintOpacity, lightMode_Active_LuminosityOpacity), + GetEffectiveLuminosityColor(lightMode_Active_Color, lightMode_Active_TintOpacity, lightMode_Active_LuminosityOpacity), + blurAmount, + hostBackdrop + ); + lightMode_Inactive_Brush = CreateBrush( + compositor, + noiceBrush, + GetEffectiveTintColor(lightMode_Inactive_Color, lightMode_Inactive_TintOpacity, lightMode_Inactive_LuminosityOpacity), + GetEffectiveLuminosityColor(lightMode_Inactive_Color, lightMode_Inactive_TintOpacity, lightMode_Inactive_LuminosityOpacity), + blurAmount, + hostBackdrop + ); + darkMode_Active_Brush = CreateBrush( + compositor, + noiceBrush, + GetEffectiveTintColor(darkMode_Active_Color, darkMode_Active_TintOpacity, darkMode_Active_LuminosityOpacity), + GetEffectiveLuminosityColor(darkMode_Active_Color, darkMode_Active_TintOpacity, darkMode_Active_LuminosityOpacity), + blurAmount, + hostBackdrop + ); + darkMode_Inactive_Brush = CreateBrush( + compositor, + noiceBrush, + GetEffectiveTintColor(darkMode_Inactive_Color, darkMode_Inactive_TintOpacity, darkMode_Inactive_LuminosityOpacity), + GetEffectiveLuminosityColor(darkMode_Inactive_Color, darkMode_Inactive_TintOpacity, darkMode_Inactive_LuminosityOpacity), + blurAmount, + hostBackdrop + ); + } + + return CDCompResources::GetBrush(useDarkMode, windowActivated); + } + catch (...) { return nullptr; } + }; + + struct CAcrylicBackdrop : CDCompBackdrop + { + inline static CAcrylicResources s_sharedResources{}; + + STDMETHOD(UpdateColorizationColor)( + bool useDarkMode, + bool windowActivated + ) override + { + if (useDarkMode) + { + if (windowActivated) { currentColor = s_sharedResources.darkMode_Active_Color; } + else { currentColor = s_sharedResources.darkMode_Inactive_Color; } + } + else + { + if (windowActivated) { currentColor = s_sharedResources.lightMode_Active_Color; } + else { currentColor = s_sharedResources.lightMode_Inactive_Color; } + } + + return S_OK; + } + HRESULT STDMETHODCALLTYPE Update( + bool useDarkMode, + bool windowActivated + ) try + { + THROW_IF_FAILED(UpdateColorizationColor(useDarkMode, windowActivated)); + THROW_IF_FAILED( + TryCrossFadeToNewBrush( + spriteVisual.Compositor(), + s_sharedResources.GetBrush(useDarkMode, windowActivated), + s_sharedResources.crossfadeTime + ) + ); + + return S_OK; + } + CATCH_RETURN() + }; + + struct CAccentAcrylicResources : CDCompResourcesBase + { + winrt::Windows::UI::Composition::CompositionSurfaceBrush noiceBrush{ nullptr }; + + HRESULT STDMETHODCALLTYPE EnsureNoiceSurfaceBrush() try + { + auto is_device_valid = [&]() + { + if (!interopDCompDevice) return false; + + BOOL valid{ FALSE }; + THROW_IF_FAILED( + interopDCompDevice.as()->CheckDeviceState( + &valid + ) + ); + + return valid == TRUE; + }; + if (!is_device_valid()) + { + interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + noiceBrush = CAcrylicResources::CreateNoiceSurfaceBrush( + interopDCompDevice.as(), + DWM::CDesktopManager::s_pDesktopManagerInstance->GetD2DDevice() + ); + } + + return S_OK; + } + CATCH_RETURN() + }; + struct CAccentAcrylicBackdrop : CAccentDCompBackdrop + { + inline static CAccentAcrylicResources s_sharedResources{}; + bool usingLuminosity{ false }; + winrt::Windows::UI::Color currenTintColor{}; + + HRESULT STDMETHODCALLTYPE UpdateBrush(const DWM::ACCENT_POLICY& policy) try + { + THROW_IF_FAILED(s_sharedResources.EnsureNoiceSurfaceBrush()); + + auto compositor{ spriteVisual.Compositor() }; + auto useLuminosity + { + MDWMBlurGlass::os::buildNumber >= 22000 && + (policy.nFlags & 2) != 0 && + ( + (policy.nAccentState == 3 && MDWMBlurGlass::os::buildNumber > 22000) || + (policy.nAccentState == 4) + ) + }; + auto tintColor{ FromAbgr(policy.nColor) }; + if ( + usingLuminosity != useLuminosity || + currenTintColor != tintColor || + interopDCompDevice != s_sharedResources.interopDCompDevice + ) + { + interopDCompDevice = s_sharedResources.interopDCompDevice; + usingLuminosity = useLuminosity; + currenTintColor = tintColor; + + auto tintOpacity{ static_cast(tintColor.A) / 255.f }; + tintColor.A = 255; + spriteVisual.Brush( + CAcrylicResources::CreateBrush( + compositor, + s_sharedResources.noiceBrush, + CAcrylicResources::GetEffectiveTintColor(tintColor, tintOpacity, useLuminosity ? std::optional{ 1.03f } : std::nullopt), + CAcrylicResources::GetEffectiveLuminosityColor(tintColor, tintOpacity, useLuminosity ? std::optional{ 1.03f } : std::nullopt), + CAcrylicBackdrop::s_sharedResources.blurAmount, + CAcrylicBackdrop::s_sharedResources.hostBackdrop + ) + ); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT STDMETHODCALLTYPE Update(const DWM::ACCENT_POLICY& policy) override try + { + THROW_IF_FAILED(UpdateBrush(policy)); + + return S_OK; + } + CATCH_RETURN() + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Backdrops/AeroBackdrop.hpp b/DWMBlurGlassExt/Backdrops/AeroBackdrop.hpp new file mode 100644 index 0000000..78a247f --- /dev/null +++ b/DWMBlurGlassExt/Backdrops/AeroBackdrop.hpp @@ -0,0 +1,311 @@ +#pragma once +#include "DCompBackdrop.hpp" +#include "../Effects/CrossFadeEffect.hpp" +#include "../Effects/GaussianBlurEffect.hpp" +#include "../Effects/ColorSourceEffect.hpp" +#include "../Effects/OpacityEffect.hpp" +#include "../Effects/BlendEffect.hpp" +#include "../Effects/ExposureEffect.hpp" +#include "../Effects/CompositeEffect.hpp" + +namespace MDWMBlurGlassExt +{ + struct CAeroResources : CDCompResources + { + winrt::Windows::UI::Color lightMode_Active_GlowColor{}; + winrt::Windows::UI::Color darkMode_Active_GlowColor{}; + winrt::Windows::UI::Color lightMode_Inactive_GlowColor{}; + winrt::Windows::UI::Color darkMode_Inactive_GlowColor{}; + + float lightMode_Active_ColorBalance{}; + float lightMode_Inactive_ColorBalance{}; + float darkMode_Active_ColorBalance{}; + float darkMode_Inactive_ColorBalance{}; + + float lightMode_Active_GlowBalance{}; + float lightMode_Inactive_GlowBalance{}; + float darkMode_Active_GlowBalance{}; + float darkMode_Inactive_GlowBalance{}; + + float Active_BlurBalance{}; + float Inactive_BlurBalance{}; + + float blurAmount{ 3.f }; + bool hostBackdrop{ false }; + + static winrt::Windows::UI::Composition::CompositionBrush CreateBrush( + const winrt::Windows::UI::Composition::Compositor& compositor, + const winrt::Windows::UI::Color& mainColor, + const winrt::Windows::UI::Color& glowColor, + float colorBalance, + float glowBalance, + float blurAmount, + float blurBalance, + bool hostBackdrop + ) try + { + // New Aero backdrop recipe by @ALTaleX531 (https://github.com/ALTaleX531/MDWMBlurGlassExt), @aubymori (normal layer fixes) + // @kfh83 for porting to DWMBlurGlass and minor modifications + + auto colorEffect{ winrt::make_self() }; + colorEffect->SetName(L"MainColor"); + colorEffect->SetColor(mainColor); + + auto colorOpacityEffect{ winrt::make_self() }; + colorOpacityEffect->SetName(L"MainColorOpacity"); + colorOpacityEffect->SetInput(*colorEffect); + colorOpacityEffect->SetOpacity(colorBalance); + + auto glowColorEffect{ winrt::make_self() }; + glowColorEffect->SetName(L"GlowColor"); + glowColorEffect->SetColor(glowColor); + + auto glowOpacityEffect{ winrt::make_self() }; + glowOpacityEffect->SetName(L"GlowColorOpacity"); + glowOpacityEffect->SetInput(*glowColorEffect); + glowOpacityEffect->SetOpacity(glowBalance); + + auto blurredBackdropBalanceEffect{ winrt::make_self() }; + blurredBackdropBalanceEffect->SetName(L"BlurBalance"); + blurredBackdropBalanceEffect->SetExposureAmount(blurBalance); + + if (hostBackdrop) + { + blurredBackdropBalanceEffect->SetInput(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"Backdrop" }); + } + else + { + auto gaussianBlurEffect{ winrt::make_self() }; + gaussianBlurEffect->SetName(L"Blur"); + gaussianBlurEffect->SetBorderMode(D2D1_BORDER_MODE_HARD); + gaussianBlurEffect->SetBlurAmount(blurAmount); + gaussianBlurEffect->SetInput(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"Backdrop" }); + blurredBackdropBalanceEffect->SetInput(*gaussianBlurEffect); + } + + auto glowBlendEffect{ winrt::make_self() }; + glowBlendEffect->SetBlendMode(D2D1_BLEND_MODE_MULTIPLY); + glowBlendEffect->SetBackground(*blurredBackdropBalanceEffect); + glowBlendEffect->SetForeground(*glowOpacityEffect); + + auto glowBalanceEffect{ winrt::make_self() }; + glowBalanceEffect->SetName(L"GlowBalance"); + glowBalanceEffect->SetExposureAmount(glowBalance / 10.f); + glowBalanceEffect->SetInput(*glowBlendEffect); + + auto compositeEffect{ winrt::make_self() }; + compositeEffect->SetCompositeMode(D2D1_COMPOSITE_MODE_SOURCE_OVER); + compositeEffect->SetName(L"Composite"); + compositeEffect->SetDestination(*glowBalanceEffect); + compositeEffect->SetSource(*colorOpacityEffect); + + auto colorBalanceEffect{ winrt::make_self() }; + colorBalanceEffect->SetName(L"ColorBalance"); + colorBalanceEffect->SetExposureAmount(colorBalance / 10.f); + colorBalanceEffect->SetInput(*compositeEffect); + + auto effectBrush{ compositor.CreateEffectFactory(*glowBalanceEffect).CreateBrush() }; + if (hostBackdrop) + { + effectBrush.SetSourceParameter(L"Backdrop", compositor.CreateHostBackdropBrush()); + } + else + { + effectBrush.SetSourceParameter(L"Backdrop", compositor.CreateBackdropBrush()); + } + + return effectBrush; + } + catch (...) { return nullptr; } + + void STDMETHODCALLTYPE ReloadParameters() + { + crossfadeTime = std::chrono::milliseconds{ g_configData.crossfadeTime }; + + darkMode_Active_Color = MakeWinrtColor(g_configData.activeBlendColorDark); + darkMode_Inactive_Color = MakeWinrtColor(g_configData.inactiveBlendColorDark); + lightMode_Active_Color = MakeWinrtColor(g_configData.activeBlendColor); + lightMode_Inactive_Color = MakeWinrtColor(g_configData.inactiveBlendColor); + + darkMode_Active_GlowColor = darkMode_Active_Color; + darkMode_Inactive_GlowColor = darkMode_Inactive_Color; + lightMode_Active_GlowColor = lightMode_Active_Color; + lightMode_Inactive_GlowColor = lightMode_Inactive_Color; + + lightMode_Active_ColorBalance = g_configData.activeColorBalance; + lightMode_Inactive_ColorBalance = g_configData.inactiveColorBalance; + darkMode_Active_ColorBalance = g_configData.activeColorBalance; + darkMode_Inactive_ColorBalance = g_configData.inactiveColorBalance; + + lightMode_Active_GlowBalance = GetFloatAlpha(g_configData.activeBlendColor); + lightMode_Inactive_GlowBalance = GetFloatAlpha(g_configData.inactiveBlendColor); + darkMode_Active_GlowBalance = GetFloatAlpha(g_configData.activeBlendColorDark); + darkMode_Inactive_GlowBalance = GetFloatAlpha(g_configData.inactiveBlendColorDark); + + Active_BlurBalance = g_configData.activeBlurBalance; + Inactive_BlurBalance = g_configData.inactiveBlurBalance; + + blurAmount = g_configData.customBlurAmount; + } + winrt::Windows::UI::Composition::CompositionBrush STDMETHODCALLTYPE GetBrush(bool useDarkMode, bool windowActivated) override try + { + auto is_device_valid = [&]() + { + if (!interopDCompDevice) return false; + + BOOL valid{ FALSE }; + THROW_IF_FAILED( + interopDCompDevice.as()->CheckDeviceState( + &valid + ) + ); + + return valid == TRUE; + }; + if (!is_device_valid()) + { + interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + ReloadParameters(); + auto compositor{ interopDCompDevice.as() }; + + lightMode_Active_Brush = CreateBrush( + compositor, + lightMode_Active_Color, + lightMode_Active_GlowColor, + lightMode_Active_ColorBalance, + lightMode_Active_GlowBalance, + blurAmount, + Active_BlurBalance, + hostBackdrop + ); + lightMode_Inactive_Brush = CreateBrush( + compositor, + lightMode_Inactive_Color, + lightMode_Inactive_GlowColor, + lightMode_Inactive_ColorBalance, + lightMode_Inactive_GlowBalance, + blurAmount, + Inactive_BlurBalance, + hostBackdrop + ); + darkMode_Active_Brush = CreateBrush( + compositor, + darkMode_Active_Color, + darkMode_Active_GlowColor, + darkMode_Active_ColorBalance, + darkMode_Active_GlowBalance, + blurAmount, + Active_BlurBalance, + hostBackdrop + ); + darkMode_Inactive_Brush = CreateBrush( + compositor, + darkMode_Inactive_Color, + darkMode_Inactive_GlowColor, + darkMode_Inactive_ColorBalance, + darkMode_Inactive_GlowBalance, + blurAmount, + Inactive_BlurBalance, + hostBackdrop + ); + } + + return CDCompResources::GetBrush(useDarkMode, windowActivated); + } + catch (...) { return nullptr; } + }; + + struct CAeroBackdrop : CDCompBackdrop + { + inline static CAeroResources s_sharedResources{}; + + STDMETHOD(UpdateColorizationColor)( + bool useDarkMode, + bool windowActivated + ) override + { + if (useDarkMode) + { + if (windowActivated) { currentColor = s_sharedResources.darkMode_Active_Color; } + else { currentColor = s_sharedResources.darkMode_Inactive_Color; } + } + else + { + if (windowActivated) { currentColor = s_sharedResources.lightMode_Active_Color; } + else { currentColor = s_sharedResources.lightMode_Inactive_Color; } + } + + return S_OK; + } + HRESULT STDMETHODCALLTYPE Update( + bool useDarkMode, + bool windowActivated + ) try + { + THROW_IF_FAILED(UpdateColorizationColor(useDarkMode, windowActivated)); + THROW_IF_FAILED( + TryCrossFadeToNewBrush( + spriteVisual.Compositor(), + s_sharedResources.GetBrush(useDarkMode, windowActivated), + s_sharedResources.crossfadeTime + ) + ); + + return S_OK; + } + CATCH_RETURN() + }; + + struct CAccentAeroResources : CDCompResourcesBase + { + + }; + struct CAccentAeroBackdrop : CAccentDCompBackdrop + { + inline static CAccentAeroResources s_sharedResources{}; + winrt::Windows::UI::Color currenGlowColor{}; + + HRESULT STDMETHODCALLTYPE UpdateBrush(const DWM::ACCENT_POLICY& policy) try + { + s_sharedResources.interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + auto compositor{ spriteVisual.Compositor() }; + auto glowColor{ FromAbgr(policy.nColor) }; + if ( + currenGlowColor != glowColor || + interopDCompDevice != s_sharedResources.interopDCompDevice + ) + { + interopDCompDevice = s_sharedResources.interopDCompDevice; + currenGlowColor = glowColor; + + spriteVisual.Brush( + CAeroResources::CreateBrush( + compositor, + CAeroBackdrop::s_sharedResources.lightMode_Active_Color, + { 255, currenGlowColor.R, currenGlowColor.G, currenGlowColor.B }, + CAeroBackdrop::s_sharedResources.lightMode_Active_ColorBalance, + static_cast(currenGlowColor.A) / 255.f, + CAeroBackdrop::s_sharedResources.blurAmount, + CAeroBackdrop::s_sharedResources.Active_BlurBalance, + CAeroBackdrop::s_sharedResources.hostBackdrop + ) + ); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT STDMETHODCALLTYPE Update(const DWM::ACCENT_POLICY& policy) override try + { + THROW_IF_FAILED(UpdateBrush(policy)); + + return S_OK; + } + CATCH_RETURN() + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Backdrops/BlurBackdrop.hpp b/DWMBlurGlassExt/Backdrops/BlurBackdrop.hpp new file mode 100644 index 0000000..ecf229b --- /dev/null +++ b/DWMBlurGlassExt/Backdrops/BlurBackdrop.hpp @@ -0,0 +1,235 @@ +#pragma once +#include "DCompBackdrop.hpp" +#include "../Effects/CrossFadeEffect.hpp" +#include "../Effects/GaussianBlurEffect.hpp" +#include "../Effects/ColorSourceEffect.hpp" +#include "../Effects/OpacityEffect.hpp" +#include "../Effects/BlendEffect.hpp" + +namespace MDWMBlurGlassExt +{ + struct CBlurResources : CDCompResources + { + float lightMode_Active_TintOpacity{}; + float lightMode_Inactive_TintOpacity{}; + float darkMode_Active_TintOpacity{}; + float darkMode_Inactive_TintOpacity{}; + float blurAmount{ 3.f }; + bool hostBackdrop{ false }; + + static winrt::Windows::UI::Composition::CompositionBrush CreateBrush( + const winrt::Windows::UI::Composition::Compositor& compositor, + const winrt::Windows::UI::Color& tintColor, + float tintOpacity, + float blurAmount, + bool hostBackdrop + ) try + { + if (static_cast(tintColor.A) * tintOpacity == 255.f) + { + return compositor.CreateColorBrush(tintColor); + } + + auto tintColorEffect{ winrt::make_self() }; + tintColorEffect->SetName(L"TintColor"); + tintColorEffect->SetColor(tintColor); + + auto tintOpacityEffect{ winrt::make_self() }; + tintOpacityEffect->SetName(L"TintOpacity"); + tintOpacityEffect->SetOpacity(tintOpacity); + tintOpacityEffect->SetInput(*tintColorEffect); + + auto colorBlendEffect{ winrt::make_self() }; + colorBlendEffect->SetBlendMode(D2D1_BLEND_MODE_MULTIPLY); + if (hostBackdrop) + { + colorBlendEffect->SetBackground(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"Backdrop" }); + } + else + { + auto gaussianBlurEffect{ winrt::make_self() }; + gaussianBlurEffect->SetName(L"Blur"); + gaussianBlurEffect->SetBorderMode(D2D1_BORDER_MODE_HARD); + gaussianBlurEffect->SetBlurAmount(blurAmount); + gaussianBlurEffect->SetInput(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"Backdrop" }); + colorBlendEffect->SetBackground(*gaussianBlurEffect); + } + colorBlendEffect->SetForeground(*tintOpacityEffect); + + auto effectBrush{ compositor.CreateEffectFactory(*colorBlendEffect).CreateBrush() }; + if (hostBackdrop) + { + effectBrush.SetSourceParameter(L"Backdrop", compositor.CreateHostBackdropBrush()); + } + else + { + effectBrush.SetSourceParameter(L"Backdrop", compositor.CreateBackdropBrush()); + } + + return effectBrush; + } + catch (...) { return nullptr; } + + void STDMETHODCALLTYPE ReloadParameters() + { + crossfadeTime = std::chrono::milliseconds{ g_configData.crossfadeTime }; + + darkMode_Active_Color = MakeWinrtColor(g_configData.activeBlendColorDark); + darkMode_Inactive_Color = MakeWinrtColor(g_configData.inactiveBlendColorDark); + lightMode_Active_Color = MakeWinrtColor(g_configData.activeBlendColor); + lightMode_Inactive_Color = MakeWinrtColor(g_configData.inactiveBlendColor); + + lightMode_Active_TintOpacity = GetFloatAlpha(g_configData.activeBlendColor); + lightMode_Inactive_TintOpacity = GetFloatAlpha(g_configData.inactiveBlendColor); + darkMode_Active_TintOpacity = GetFloatAlpha(g_configData.activeBlendColorDark); + darkMode_Inactive_TintOpacity = GetFloatAlpha(g_configData.inactiveBlendColorDark); + + blurAmount = g_configData.customBlurAmount; + } + winrt::Windows::UI::Composition::CompositionBrush STDMETHODCALLTYPE GetBrush(bool useDarkMode, bool windowActivated) override try + { + auto is_device_valid = [&]() + { + if (!interopDCompDevice) return false; + + BOOL valid{ FALSE }; + THROW_IF_FAILED( + interopDCompDevice.as()->CheckDeviceState( + &valid + ) + ); + + return valid == TRUE; + }; + if (!is_device_valid()) + { + interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + ReloadParameters(); + auto compositor{ interopDCompDevice.as() }; + + lightMode_Active_Brush = CreateBrush( + compositor, + lightMode_Active_Color, + lightMode_Active_TintOpacity, + blurAmount, + hostBackdrop + ); + lightMode_Inactive_Brush = CreateBrush( + compositor, + lightMode_Inactive_Color, + lightMode_Inactive_TintOpacity, + blurAmount, + hostBackdrop + ); + darkMode_Active_Brush = CreateBrush( + compositor, + darkMode_Active_Color, + darkMode_Active_TintOpacity, + blurAmount, + hostBackdrop + ); + darkMode_Inactive_Brush = CreateBrush( + compositor, + darkMode_Inactive_Color, + darkMode_Inactive_TintOpacity, + blurAmount, + hostBackdrop + ); + } + + return CDCompResources::GetBrush(useDarkMode, windowActivated); + } + catch (...) { return nullptr; } + }; + + struct CBlurBackdrop : CDCompBackdrop + { + inline static CBlurResources s_sharedResources{}; + + STDMETHOD(UpdateColorizationColor)( + bool useDarkMode, + bool windowActivated + ) override + { + if (useDarkMode) + { + if (windowActivated) { currentColor = s_sharedResources.darkMode_Active_Color; } + else { currentColor = s_sharedResources.darkMode_Inactive_Color; } + } + else + { + if (windowActivated) { currentColor = s_sharedResources.lightMode_Active_Color; } + else { currentColor = s_sharedResources.lightMode_Inactive_Color; } + } + + return S_OK; + } + HRESULT STDMETHODCALLTYPE Update( + bool useDarkMode, + bool windowActivated + ) try + { + THROW_IF_FAILED(UpdateColorizationColor(useDarkMode, windowActivated)); + THROW_IF_FAILED( + TryCrossFadeToNewBrush( + spriteVisual.Compositor(), + s_sharedResources.GetBrush(useDarkMode, windowActivated), + s_sharedResources.crossfadeTime + ) + ); + + return S_OK; + } + CATCH_RETURN() + }; + + struct CAccentBlurResources : CDCompResourcesBase + { + + }; + struct CAccentBlurBackdrop : CAccentDCompBackdrop + { + inline static CAccentBlurResources s_sharedResources{}; + winrt::Windows::UI::Color currenTintColor{}; + + HRESULT STDMETHODCALLTYPE UpdateBrush(const DWM::ACCENT_POLICY& policy) try + { + s_sharedResources.interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + auto compositor{ spriteVisual.Compositor() }; + auto tintColor{ FromAbgr(policy.nColor) }; + if ( + currenTintColor != tintColor || + interopDCompDevice != s_sharedResources.interopDCompDevice + ) + { + interopDCompDevice = s_sharedResources.interopDCompDevice; + currenTintColor = tintColor; + + spriteVisual.Brush( + CBlurResources::CreateBrush( + compositor, + tintColor, + 1.f, + CBlurBackdrop::s_sharedResources.blurAmount, + CBlurBackdrop::s_sharedResources.hostBackdrop + ) + ); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT STDMETHODCALLTYPE Update(const DWM::ACCENT_POLICY& policy) override try + { + THROW_IF_FAILED(UpdateBrush(policy)); + + return S_OK; + } + CATCH_RETURN() + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Backdrops/DCompBackdrop.hpp b/DWMBlurGlassExt/Backdrops/DCompBackdrop.hpp new file mode 100644 index 0000000..23dcdc7 --- /dev/null +++ b/DWMBlurGlassExt/Backdrops/DCompBackdrop.hpp @@ -0,0 +1,177 @@ +#pragma once +#include "DWMStruct.h" +#include "../Effects/CrossFadeEffect.hpp" +#include "ColorConversion.hpp" +#include "CommonDef.h" + +namespace MDWMBlurGlassExt +{ + using namespace CommonDef; + winrt::Windows::UI::Color MakeWinrtColor(COLORREF color, bool rgb = true) + { + return + { + rgb ? (BYTE)0xFF : BYTE((color >> 24) & 0xff), + GetRValue(color), + GetGValue(color), + GetBValue(color), + }; + } + float GetFloatAlpha(COLORREF color) + { + return float(BYTE((color >> 24) & 0xff)) / 255.f; + } + + struct CDCompResourcesBase + { + winrt::com_ptr interopDCompDevice{ nullptr }; + virtual void ReloadParameters() {} + }; + struct CDCompResources : CDCompResourcesBase + { + winrt::Windows::UI::Composition::CompositionBrush lightMode_Active_Brush{ nullptr }; + winrt::Windows::UI::Composition::CompositionBrush darkMode_Active_Brush{ nullptr }; + winrt::Windows::UI::Composition::CompositionBrush lightMode_Inactive_Brush{ nullptr }; + winrt::Windows::UI::Composition::CompositionBrush darkMode_Inactive_Brush{ nullptr }; + std::chrono::milliseconds crossfadeTime{ 87 }; + winrt::Windows::UI::Color lightMode_Active_Color{}; + winrt::Windows::UI::Color darkMode_Active_Color{}; + winrt::Windows::UI::Color lightMode_Inactive_Color{}; + winrt::Windows::UI::Color darkMode_Inactive_Color{}; + + static winrt::Windows::UI::Composition::CompositionBrush CreateCrossFadeEffectBrush( + const winrt::Windows::UI::Composition::Compositor& compositor, + const winrt::Windows::UI::Composition::CompositionBrush& from, + const winrt::Windows::UI::Composition::CompositionBrush& to + ) + { + auto crossFadeEffect{ winrt::make_self() }; + crossFadeEffect->SetName(L"Crossfade"); + crossFadeEffect->SetSource(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"From" }); + crossFadeEffect->SetDestination(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"To" }); + crossFadeEffect->SetWeight(0); + + auto crossFadeEffectBrush{ compositor.CreateEffectFactory( *crossFadeEffect, {L"Crossfade.Weight"} ).CreateBrush() }; + crossFadeEffectBrush.Comment(L"Crossfade"); + crossFadeEffectBrush.SetSourceParameter(L"From", from); + crossFadeEffectBrush.SetSourceParameter(L"To", to); + return crossFadeEffectBrush; + } + static winrt::Windows::UI::Composition::ScalarKeyFrameAnimation CreateCrossFadeAnimation( + const winrt::Windows::UI::Composition::Compositor& compositor, + winrt::Windows::Foundation::TimeSpan const& crossfadeTime + ) + { + auto animation{ compositor.CreateScalarKeyFrameAnimation() }; + auto linearEasing{ compositor.CreateLinearEasingFunction() }; + animation.InsertKeyFrame(0.0f, 0.0f, linearEasing); + animation.InsertKeyFrame(1.0f, 1.0f, linearEasing); + animation.Duration(crossfadeTime); + return animation; + } + virtual winrt::Windows::UI::Composition::CompositionBrush STDMETHODCALLTYPE GetBrush(bool useDarkMode, bool windowActivated) + { + if (useDarkMode) + { + if (windowActivated) { return darkMode_Active_Brush; } + else { return darkMode_Inactive_Brush; } + } + else + { + if (windowActivated) { return lightMode_Active_Brush; } + else { return lightMode_Inactive_Brush; } + } + + return nullptr; + } + }; + + struct CDCompBackdropBase + { + winrt::Windows::UI::Composition::SpriteVisual spriteVisual{ nullptr }; + + STDMETHOD(Initialize)( + winrt::Windows::UI::Composition::VisualCollection& visualCollection + ) + { + auto compositor{ visualCollection.Compositor() }; + spriteVisual = compositor.CreateSpriteVisual(); + spriteVisual.RelativeSizeAdjustment({ 1.f, 1.f }); + visualCollection.InsertAtTop(spriteVisual); + + return S_OK; + } + virtual ~CDCompBackdropBase() = default; + }; + + struct CDCompBackdrop : CDCompBackdropBase + { + winrt::Windows::UI::Composition::CompositionBrush currentBrush{ nullptr }; + winrt::Windows::UI::Color currentColor{}; + + STDMETHOD(TryCrossFadeToNewBrush)( + const winrt::Windows::UI::Composition::Compositor& compositor, + const winrt::Windows::UI::Composition::CompositionBrush& newBrush, + std::chrono::milliseconds crossfadeTime + ) try + { + if (currentBrush != newBrush) + { + if (currentBrush && crossfadeTime.count()) + { + const auto crossfadeBrush + { + CDCompResources::CreateCrossFadeEffectBrush( + compositor, + currentBrush, + newBrush + ) + }; + currentBrush = newBrush; + spriteVisual.Brush(crossfadeBrush); + + crossfadeBrush.StartAnimation( + L"Crossfade.Weight", + CDCompResources::CreateCrossFadeAnimation( + compositor, + crossfadeTime + ) + ); + } + else + { + currentBrush = newBrush; + spriteVisual.Brush(currentBrush); + } + } + + return S_OK; + } + CATCH_RETURN() + + STDMETHOD(UpdateColorizationColor)( + bool useDarkMode, + bool windowActivated + ) PURE; + STDMETHOD(Update)( + bool useDarkMode, + bool windowActivated + ) PURE; + }; + struct CAccentDCompBackdrop : CDCompBackdropBase + { + winrt::com_ptr interopDCompDevice{ nullptr }; + inline static winrt::Windows::UI::Color FromAbgr(DWORD gradientColor) + { + auto abgr{ reinterpret_cast(&gradientColor) }; + return + { + abgr[3], + abgr[0], + abgr[1], + abgr[2] + }; + } + STDMETHOD(Update)(const DWM::ACCENT_POLICY& policy) PURE; + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Backdrops/GlassReflectionBackdrop.hpp b/DWMBlurGlassExt/Backdrops/GlassReflectionBackdrop.hpp new file mode 100644 index 0000000..fde03e0 --- /dev/null +++ b/DWMBlurGlassExt/Backdrops/GlassReflectionBackdrop.hpp @@ -0,0 +1,232 @@ +#pragma once +#include "DCompBackdrop.hpp" +#include + +namespace MDWMBlurGlassExt +{ + struct CGlassReflectionResources : CDCompResourcesBase + { + winrt::Windows::UI::Composition::CompositionDrawingSurface drawingSurface{ nullptr }; + float parallaxIntensity{ 0.1f }; + float glassIntensity{ 0.8f }; + + void ReloadParameters() override + { + glassIntensity = g_configData.glassIntensity; + } + HRESULT STDMETHODCALLTYPE EnsureGlassSurface() try + { + auto is_device_valid = [&]() + { + if (!interopDCompDevice) return false; + + BOOL valid{ FALSE }; + THROW_IF_FAILED( + interopDCompDevice.as()->CheckDeviceState( + &valid + ) + ); + + return valid == TRUE; + }; + if (!is_device_valid()) + { + interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + ReloadParameters(); + auto compositor{ interopDCompDevice.as() }; + winrt::Windows::UI::Composition::CompositionGraphicsDevice graphicsDevice{ nullptr }; + THROW_IF_FAILED( + compositor.as()->CreateGraphicsDevice( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetD2DDevice(), + reinterpret_cast(winrt::put_abi(graphicsDevice)) + ) + ); + + WCHAR filePath[MAX_PATH + 1]{}; + GetModuleFileName(wil::GetModuleInstanceHandle(), filePath, MAX_PATH); + PathCchRemoveFileSpec(filePath, MAX_PATH); + PathCchAppend(filePath, MAX_PATH, L"data\\AeroPeek.png"); + + wil::unique_hfile file{ CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0) }; + THROW_LAST_ERROR_IF(!file.is_valid()); + + LARGE_INTEGER fileSize{}; + THROW_IF_WIN32_BOOL_FALSE(GetFileSizeEx(file.get(), &fileSize)); + + auto buffer{ std::make_unique(static_cast(fileSize.QuadPart)) }; + THROW_IF_WIN32_BOOL_FALSE(ReadFile(file.get(), buffer.get(), static_cast(fileSize.QuadPart), nullptr, nullptr)); + winrt::com_ptr stream{ SHCreateMemStream(buffer.get(), static_cast(fileSize.QuadPart)), winrt::take_ownership_from_abi }; + THROW_LAST_ERROR_IF_NULL(stream); + + winrt::com_ptr wicFactory{ nullptr }; + wicFactory.copy_from(DWM::CDesktopManager::s_pDesktopManagerInstance->GetWICFactory()); + winrt::com_ptr wicDecoder{ nullptr }; + THROW_IF_FAILED(wicFactory->CreateDecoderFromStream(stream.get(), &GUID_VendorMicrosoft, WICDecodeMetadataCacheOnDemand, wicDecoder.put())); + winrt::com_ptr wicFrame{ nullptr }; + THROW_IF_FAILED(wicDecoder->GetFrame(0, wicFrame.put())); + winrt::com_ptr wicConverter{ nullptr }; + THROW_IF_FAILED(wicFactory->CreateFormatConverter(wicConverter.put())); + winrt::com_ptr wicPalette{ nullptr }; + THROW_IF_FAILED( + wicConverter->Initialize( + wicFrame.get(), + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + wicPalette.get(), + 0, WICBitmapPaletteTypeCustom + ) + ); + winrt::com_ptr wicBitmap{ nullptr }; + THROW_IF_FAILED(wicFactory->CreateBitmapFromSource(wicConverter.get(), WICBitmapCreateCacheOption::WICBitmapNoCache, wicBitmap.put())); + + UINT width{ 0 }, height{ 0 }; + THROW_IF_FAILED(wicBitmap->GetSize(&width, &height)); + drawingSurface = graphicsDevice.CreateDrawingSurface( + { static_cast(width), static_cast(height) }, + winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized, + winrt::Windows::Graphics::DirectX::DirectXAlphaMode::Premultiplied + ); + auto drawingSurfaceInterop{ drawingSurface.as() }; + POINT offset = { 0, 0 }; + winrt::com_ptr d2dContext{ nullptr }; + THROW_IF_FAILED( + drawingSurfaceInterop->BeginDraw(nullptr, IID_PPV_ARGS(d2dContext.put()), &offset) + ); + d2dContext->Clear(); + winrt::com_ptr d2dBitmap{ nullptr }; + d2dContext->CreateBitmapFromWicBitmap( + wicBitmap.get(), + D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_NONE, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED) + ), + d2dBitmap.put() + ); + d2dContext->DrawBitmap(d2dBitmap.get()); + THROW_IF_FAILED( + drawingSurfaceInterop->EndDraw() + ); + + return S_OK; + } + + return S_OK; + } + CATCH_RETURN() + }; + + struct CGlassReflectionBackdrop : CDCompBackdropBase + { + inline static CGlassReflectionResources s_sharedResources{}; + + winrt::com_ptr interopDCompDevice{ nullptr }; + winrt::Windows::Foundation::Numerics::float2 fixedOffset{}; + RECT currentWindowRect{}; + RECT currentMonitorRect{}; + HMONITOR currentMonitor{ nullptr }; + winrt::Windows::UI::Composition::CompositionSurfaceBrush glassSurfaceBrush{ nullptr }; + + STDMETHOD(Initialize)( + winrt::Windows::UI::Composition::VisualCollection& visualCollection + ) override try + { + THROW_IF_FAILED(CDCompBackdropBase::Initialize(visualCollection)); + THROW_IF_FAILED(s_sharedResources.EnsureGlassSurface()); + THROW_HR_IF_NULL(E_POINTER, s_sharedResources.drawingSurface); + glassSurfaceBrush = spriteVisual.Compositor().CreateSurfaceBrush(s_sharedResources.drawingSurface); + glassSurfaceBrush.Stretch(winrt::Windows::UI::Composition::CompositionStretch::None); + glassSurfaceBrush.HorizontalAlignmentRatio(0.f); + glassSurfaceBrush.VerticalAlignmentRatio(0.f); + spriteVisual.Brush(glassSurfaceBrush); + spriteVisual.Opacity(s_sharedResources.glassIntensity); + + return S_OK; + } + CATCH_RETURN() + + HRESULT STDMETHODCALLTYPE Update(DWM::CTopLevelWindow* window) try + { + THROW_IF_FAILED(s_sharedResources.EnsureGlassSurface()); + THROW_HR_IF_NULL(E_POINTER, s_sharedResources.drawingSurface); + if (interopDCompDevice != s_sharedResources.interopDCompDevice) + { + interopDCompDevice = s_sharedResources.interopDCompDevice; + glassSurfaceBrush.Surface(s_sharedResources.drawingSurface); + spriteVisual.Opacity(s_sharedResources.glassIntensity); + } + + RECT windowRect{}; + THROW_HR_IF_NULL(E_INVALIDARG, window->GetActualWindowRect(&windowRect, false, true, false)); + + HWND hwnd{ window->GetData()->GetHWND() }; + HMONITOR monitor{ MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) }; + THROW_LAST_ERROR_IF_NULL(monitor); + + RECT monitorRect{}; + MONITORINFO mi{ sizeof(MONITORINFO) }; + THROW_IF_WIN32_BOOL_FALSE(GetMonitorInfoW(monitor, &mi)); + + auto surfaceSize{ s_sharedResources.drawingSurface.SizeInt32() }; + if (currentMonitor != monitor || !EqualRect(¤tMonitorRect, &mi.rcMonitor)) + { + auto scaleFactor + { + [&]() + { + float factor{1.f}; + + auto scaledWidth{ static_cast(surfaceSize.Width) * static_cast(wil::rect_height(mi.rcMonitor)) * (1 + s_sharedResources.parallaxIntensity) / static_cast(surfaceSize.Height) }; + factor = scaledWidth / static_cast(surfaceSize.Width); + + if (scaledWidth < static_cast(wil::rect_width(mi.rcMonitor)) * (1 + s_sharedResources.parallaxIntensity)) + { + scaledWidth = static_cast(wil::rect_width(mi.rcMonitor)) * (1 + s_sharedResources.parallaxIntensity); + factor = scaledWidth / static_cast(surfaceSize.Width); + } + + return factor; + } () + }; + glassSurfaceBrush.Scale( + winrt::Windows::Foundation::Numerics::float2{ scaleFactor, scaleFactor } + ); + winrt::Windows::Foundation::Numerics::float2 scaledSize + { + static_cast(surfaceSize.Width) * scaleFactor, + static_cast(surfaceSize.Height) * scaleFactor + }; + + fixedOffset = + { + (static_cast(wil::rect_width(mi.rcMonitor)) * (1.f + s_sharedResources.parallaxIntensity) - scaledSize.x) / 2.f, + (static_cast(wil::rect_height(mi.rcMonitor)) * (1.f + s_sharedResources.parallaxIntensity) - scaledSize.y) / 2.f + }; + currentMonitor = monitor; + currentMonitorRect = mi.rcMonitor; + } + if ((currentWindowRect.left != windowRect.left) || (currentWindowRect.top != windowRect.top)) + { + MARGINS margins{}; + window->GetBorderMargins(&margins); + glassSurfaceBrush.Offset( + winrt::Windows::Foundation::Numerics::float2 + { + -static_cast(windowRect.left - mi.rcMonitor.left) * (1.f + s_sharedResources.parallaxIntensity) + + //static_cast(IsMaximized(hwnd) ? margins.cxLeftWidth : 0.f) + + fixedOffset.x, + -static_cast(windowRect.top - mi.rcMonitor.top) * (1.f + s_sharedResources.parallaxIntensity) + + //static_cast(IsMaximized(hwnd) ? margins.cyTopHeight : 0.f) + + fixedOffset.y + } + ); + + currentWindowRect = windowRect; + } + + return S_OK; + } + CATCH_RETURN() + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Backdrops/MicaBackdrop.hpp b/DWMBlurGlassExt/Backdrops/MicaBackdrop.hpp new file mode 100644 index 0000000..69a964c --- /dev/null +++ b/DWMBlurGlassExt/Backdrops/MicaBackdrop.hpp @@ -0,0 +1,247 @@ +#pragma once +#include "DCompBackdrop.hpp" +#include "../Effects/CrossFadeEffect.hpp" +#include "../Effects/GaussianBlurEffect.hpp" +#include "../Effects/ColorSourceEffect.hpp" +#include "../Effects/OpacityEffect.hpp" +#include "../Effects/BlendEffect.hpp" +#include "../Common/VersionHelper.h" + +namespace MDWMBlurGlassExt +{ + struct CMicaResources : CDCompResources + { + float lightMode_Active_TintOpacity{}; + float lightMode_Inactive_TintOpacity{}; + float darkMode_Active_TintOpacity{}; + float darkMode_Inactive_TintOpacity{}; + float lightMode_Active_LuminosityOpacity{}; + float lightMode_Inactive_LuminosityOpacity{}; + float darkMode_Active_LuminosityOpacity{}; + float darkMode_Inactive_LuminosityOpacity{}; + + static winrt::Windows::UI::Composition::CompositionBrush CreateBrush( + const winrt::Windows::UI::Composition::Compositor& compositor, + const winrt::Windows::UI::Color& tintColor, + const winrt::Windows::UI::Color& luminosityColor, + float tintOpacity, + float luminosityOpacity + ) try + { + if (static_cast(tintColor.A) * tintOpacity == 255.f) + { + return compositor.CreateColorBrush(tintColor); + } + + auto tintColorEffect{ winrt::make_self() }; + tintColorEffect->SetName(L"TintColor"); + tintColorEffect->SetColor(tintColor); + + auto tintOpacityEffect{ winrt::make_self() }; + tintOpacityEffect->SetName(L"TintOpacity"); + tintOpacityEffect->SetOpacity(tintOpacity); + tintOpacityEffect->SetInput(*tintColorEffect); + + auto luminosityColorEffect{ winrt::make_self() }; + luminosityColorEffect->SetColor(tintColor); + + auto luminosityOpacityEffect{ winrt::make_self() }; + luminosityOpacityEffect->SetName(L"LuminosityOpacity"); + luminosityOpacityEffect->SetOpacity(luminosityOpacity); + luminosityOpacityEffect->SetInput(*luminosityColorEffect); + + auto luminosityBlendEffect{ winrt::make_self() }; + luminosityBlendEffect->SetBlendMode(D2D1_BLEND_MODE_COLOR); + luminosityBlendEffect->SetBackground(winrt::Windows::UI::Composition::CompositionEffectSourceParameter{ L"BlurredWallpaperBackdrop" }); + luminosityBlendEffect->SetForeground(*luminosityOpacityEffect); + + auto colorBlendEffect{ winrt::make_self() }; + colorBlendEffect->SetBlendMode(D2D1_BLEND_MODE_LUMINOSITY); + colorBlendEffect->SetBackground(*luminosityBlendEffect); + colorBlendEffect->SetForeground(*tintOpacityEffect); + + auto micaEffectBrush{ compositor.CreateEffectFactory(*colorBlendEffect).CreateBrush() }; + micaEffectBrush.SetSourceParameter(L"BlurredWallpaperBackdrop", compositor.TryCreateBlurredWallpaperBackdropBrush()); + + return micaEffectBrush; + } + catch (...) { return nullptr; } + + void STDMETHODCALLTYPE ReloadParameters() + { + crossfadeTime = std::chrono::milliseconds{ g_configData.crossfadeTime }; + + darkMode_Active_Color = MakeWinrtColor(g_configData.activeBlendColorDark); + darkMode_Inactive_Color = MakeWinrtColor(g_configData.inactiveBlendColorDark); + lightMode_Active_Color = MakeWinrtColor(g_configData.activeBlendColor); + lightMode_Inactive_Color = MakeWinrtColor(g_configData.inactiveBlendColor); + + lightMode_Active_TintOpacity = GetFloatAlpha(g_configData.activeBlendColor); + lightMode_Inactive_TintOpacity = GetFloatAlpha(g_configData.inactiveBlendColor); + darkMode_Active_TintOpacity = GetFloatAlpha(g_configData.activeBlendColorDark); + darkMode_Inactive_TintOpacity = GetFloatAlpha(g_configData.inactiveBlendColorDark); + + lightMode_Active_LuminosityOpacity = g_configData.luminosityOpacity; + lightMode_Inactive_LuminosityOpacity = g_configData.luminosityOpacity; + darkMode_Active_LuminosityOpacity = g_configData.luminosityOpacity; + darkMode_Inactive_LuminosityOpacity = g_configData.luminosityOpacity; + } + winrt::Windows::UI::Composition::CompositionBrush STDMETHODCALLTYPE GetBrush(bool useDarkMode, bool windowActivated) override try + { + auto is_device_valid = [&]() + { + if (!interopDCompDevice) return false; + + BOOL valid{ FALSE }; + THROW_IF_FAILED( + interopDCompDevice.as()->CheckDeviceState( + &valid + ) + ); + + return valid == TRUE; + }; + if (!is_device_valid()) + { + interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + ReloadParameters(); + auto compositor{ interopDCompDevice.as() }; + + lightMode_Active_Brush = CreateBrush( + compositor, + lightMode_Active_Color, + lightMode_Active_Color, + lightMode_Active_TintOpacity, + lightMode_Active_LuminosityOpacity + ); + lightMode_Inactive_Brush = CreateBrush( + compositor, + lightMode_Inactive_Color, + lightMode_Inactive_Color, + lightMode_Inactive_TintOpacity, + lightMode_Inactive_LuminosityOpacity + ); + darkMode_Active_Brush = CreateBrush( + compositor, + darkMode_Active_Color, + darkMode_Active_Color, + darkMode_Active_TintOpacity, + darkMode_Active_LuminosityOpacity + ); + darkMode_Inactive_Brush = CreateBrush( + compositor, + darkMode_Inactive_Color, + darkMode_Inactive_Color, + darkMode_Inactive_TintOpacity, + darkMode_Inactive_LuminosityOpacity + ); + } + + return CDCompResources::GetBrush(useDarkMode, windowActivated); + } + catch (...) { return nullptr; } + }; + + struct CMicaBackdrop : CDCompBackdrop + { + inline static CMicaResources s_sharedResources{}; + + STDMETHOD(UpdateColorizationColor)( + bool useDarkMode, + bool windowActivated + ) override + { + if (useDarkMode) + { + if (windowActivated) { currentColor = s_sharedResources.darkMode_Active_Color; } + else { currentColor = s_sharedResources.darkMode_Inactive_Color; } + } + else + { + if (windowActivated) { currentColor = s_sharedResources.lightMode_Active_Color; } + else { currentColor = s_sharedResources.lightMode_Inactive_Color; } + } + + return S_OK; + } + HRESULT STDMETHODCALLTYPE Update( + bool useDarkMode, + bool windowActivated + ) try + { + THROW_IF_FAILED(UpdateColorizationColor(useDarkMode, windowActivated)); + THROW_IF_FAILED( + TryCrossFadeToNewBrush( + spriteVisual.Compositor(), + s_sharedResources.GetBrush(useDarkMode, windowActivated), + s_sharedResources.crossfadeTime + ) + ); + + return S_OK; + } + CATCH_RETURN() + }; + + struct CAccentMicaResources : CDCompResourcesBase + { + + }; + struct CAccentMicaBackdrop : CAccentDCompBackdrop + { + inline static CAccentMicaResources s_sharedResources{}; + bool usingLuminosity{ false }; + winrt::Windows::UI::Color currenTintColor{}; + + HRESULT STDMETHODCALLTYPE UpdateBrush(const DWM::ACCENT_POLICY& policy) try + { + s_sharedResources.interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + auto compositor{ spriteVisual.Compositor() }; + auto useLuminosity + { + MDWMBlurGlass::os::buildNumber >= 22000 && + (policy.nFlags & 2) != 0 && + ( + (policy.nAccentState == 3 && MDWMBlurGlass::os::buildNumber > 22000) || + (policy.nAccentState == 4) + ) + }; + auto tintColor{ FromAbgr(policy.nColor) }; + if ( + usingLuminosity != useLuminosity || + currenTintColor != tintColor || + interopDCompDevice != s_sharedResources.interopDCompDevice + ) + { + interopDCompDevice = s_sharedResources.interopDCompDevice; + usingLuminosity = useLuminosity; + currenTintColor = tintColor; + + spriteVisual.Brush( + CMicaResources::CreateBrush( + compositor, + tintColor, + useLuminosity ? winrt::Windows::UI::Color{ 255, tintColor.R, tintColor.G, tintColor.B } : tintColor, + 1.f, + 1.f + ) + ); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT STDMETHODCALLTYPE Update(const DWM::ACCENT_POLICY& policy) override try + { + THROW_IF_FAILED(UpdateBrush(policy)); + + return S_OK; + } + CATCH_RETURN() + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Backdrops/uDwmBackdrop.hpp b/DWMBlurGlassExt/Backdrops/uDwmBackdrop.hpp new file mode 100644 index 0000000..038e4f0 --- /dev/null +++ b/DWMBlurGlassExt/Backdrops/uDwmBackdrop.hpp @@ -0,0 +1,56 @@ +#pragma once +#include "DWMStruct.h" +#include + +namespace MDWMBlurGlassExt +{ + struct CSharedVisual + { + winrt::com_ptr udwmVisual{ nullptr }; + winrt::com_ptr dcompVisual{ nullptr }; + winrt::com_ptr interopCompositionTarget{ nullptr }; + winrt::Windows::UI::Composition::LayerVisual layerVisual{ nullptr }; + + HRESULT STDMETHODCALLTYPE InitializeDCompAnduDwmVisual(DCompPrivate::IDCompositionDesktopDevicePartner* requestedInteropDCompDevice) try + { + winrt::com_ptr interopDCompDevice{ nullptr }; + interopDCompDevice.copy_from(requestedInteropDCompDevice); + + THROW_IF_FAILED( + interopDCompDevice->CreateSharedResource( + IID_PPV_ARGS(interopCompositionTarget.put()) + ) + ); + + auto interopCompositor{ interopDCompDevice.as() }; + + THROW_IF_FAILED(interopDCompDevice->CreateVisual(dcompVisual.put())); + THROW_IF_FAILED( + dcompVisual->SetCompositeMode(DCOMPOSITION_COMPOSITE_MODE_SOURCE_OVER) + ); + THROW_IF_FAILED( + dcompVisual->SetBitmapInterpolationMode(DCOMPOSITION_BITMAP_INTERPOLATION_MODE_LINEAR) + ); + THROW_IF_FAILED( + dcompVisual->SetBorderMode(DCOMPOSITION_BORDER_MODE_SOFT) + ); + + layerVisual = interopCompositor.CreateLayerVisual(); + auto interopVisual{ dcompVisual.as() }; + interopVisual->GetVisualCollection().InsertAtBottom(layerVisual); + + THROW_IF_FAILED(interopCompositionTarget->SetRoot(dcompVisual.get())); + THROW_IF_FAILED(interopDCompDevice->Commit()); + + wil::unique_handle resourceHandle{ nullptr }; + THROW_IF_FAILED( + interopDCompDevice->OpenSharedResourceHandle(interopCompositionTarget.get(), resourceHandle.put()) + ); + + THROW_IF_FAILED(DWM::CVisual::CreateFromSharedHandle(resourceHandle.get(), udwmVisual.put())); + + return S_OK; + } + CATCH_RETURN() + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Common/ColorConversion.cpp b/DWMBlurGlassExt/Common/ColorConversion.cpp new file mode 100644 index 0000000..f2129d5 --- /dev/null +++ b/DWMBlurGlassExt/Common/ColorConversion.cpp @@ -0,0 +1,318 @@ +#include "ColorConversion.hpp" +#include "strsafe.h" +#include "../Helper/Helper.h" + +MDWMBlurGlassExt::Rgb::Rgb(double r, double g, double b) : r{ r }, g{ g }, b{ b } +{ +} + +MDWMBlurGlassExt::Hsv::Hsv(double h, double s, double v) : h{ h }, s{ s }, v{ v } +{ +} + +std::optional MDWMBlurGlassExt::TryParseInt(const std::wstring_view& s) +{ + return TryParseInt(s, 10 /* base */); +} + +std::optional MDWMBlurGlassExt::TryParseInt(const std::wstring_view& str, int base) +{ + // If we have a zero-length string, then we can immediately know + // that this is not a valid integer. + if (*str.data() == '\0') + { + return std::nullopt; + } + + wchar_t* end; + + // wcstoll takes in a string and converts as much as it as it can to an integer value, + // returning a pointer to the first element that it wasn't able to consider part of an integer. + // If we got all the way to the end of the string, then the whole thing was a valid string. + auto result = wcstoul(str.data(), &end, base); + if (*end == '\0') + { + return result; + } + + return std::nullopt; +} + +MDWMBlurGlassExt::Hsv MDWMBlurGlassExt::RgbToHsv(const Rgb& rgb) +{ + double hue = 0; + double saturation = 0; + double value = 0; + + const double max = rgb.r >= rgb.g ? (rgb.r >= rgb.b ? rgb.r : rgb.b) : (rgb.g >= rgb.b ? rgb.g : rgb.b); + const double min = rgb.r <= rgb.g ? (rgb.r <= rgb.b ? rgb.r : rgb.b) : (rgb.g <= rgb.b ? rgb.g : rgb.b); + + // The value, a number between 0 and 1, is the largest of R, G, and B (divided by 255). + // Conceptually speaking, it represents how much color is present. + // If at least one of R, G, B is 255, then there exists as much color as there can be. + // If RGB = (0, 0, 0), then there exists no color at all - a value of zero corresponds + // to black (i.e., the absence of any color). + value = max; + + // The "chroma" of the color is a value directly proportional to the extent to which + // the color diverges from greyscale. If, for example, we have RGB = (255, 255, 0), + // then the chroma is maximized - this is a pure yellow, no grey of any kind. + // On the other hand, if we have RGB = (128, 128, 128), then the chroma being zero + // implies that this color is pure greyscale, with no actual hue to be found. + const double chroma = max - min; + + // If the chrome is zero, then hue is technically undefined - a greyscale color + // has no hue. For the sake of convenience, we'll just set hue to zero, since + // it will be unused in this circumstance. Since the color is purely grey, + // saturation is also equal to zero - you can think of saturation as basically + // a measure of hue intensity, such that no hue at all corresponds to a + // nonexistent intensity. + if (chroma == 0) + { + hue = 0.0; + saturation = 0.0; + } + else + { + // In this block, hue is properly defined, so we'll extract both hue + // and saturation information from the RGB color. + + // Hue can be thought of as a cyclical thing, between 0 degrees and 360 degrees. + // A hue of 0 degrees is red; 120 degrees is green; 240 degrees is blue; and 360 is back to red. + // Every other hue is somewhere between either red and green, green and blue, and blue and red, + // so every other hue can be thought of as an angle on this color wheel. + // These if/else statements determines where on this color wheel our color lies. + if (rgb.r == max) + { + // If the red channel is the most pronounced channel, then we exist + // somewhere between (-60, 60) on the color wheel - i.e., the section around 0 degrees + // where red dominates. We figure out where in that section we are exactly + // by considering whether the green or the blue channel is greater - by subtracting green from blue, + // then if green is greater, we'll nudge ourselves closer to 60, whereas if blue is greater, then + // we'll nudge ourselves closer to -60. We then divide by chroma (which will actually make the result larger, + // since chroma is a value between 0 and 1) to normalize the value to ensure that we get the right hue + // even if we're very close to greyscale. + hue = 60 * (rgb.g - rgb.b) / chroma; + } + else if (rgb.g == max) + { + // We do the exact same for the case where the green channel is the most pronounced channel, + // only this time we want to see if we should tilt towards the blue direction or the red direction. + // We add 120 to center our value in the green third of the color wheel. + hue = 120 + 60 * (rgb.b - rgb.r) / chroma; + } + else // rgb.b == max + { + // And we also do the exact same for the case where the blue channel is the most pronounced channel, + // only this time we want to see if we should tilt towards the red direction or the green direction. + // We add 240 to center our value in the blue third of the color wheel. + hue = 240 + 60 * (rgb.r - rgb.g) / chroma; + } + + // Since we want to work within the range [0, 360), we'll add 360 to any value less than zero - + // this will bump red values from within -60 to -1 to 300 to 359. The hue is the same at both values. + if (hue < 0.0) + { + hue += 360.0; + } + + // The saturation, our final HSV axis, can be thought of as a value between 0 and 1 indicating how intense our color is. + // To find it, we divide the chroma - the distance between the minimum and the maximum RGB channels - by the maximum channel (i.e., the value). + // This effectively normalizes the chroma - if the maximum is 0.5 and the minimum is 0, the saturation will be (0.5 - 0) / 0.5 = 1, + // meaning that although this color is not as bright as it can be, the dark color is as intense as it possibly could be. + // If, on the other hand, the maximum is 0.5 and the minimum is 0.25, then the saturation will be (0.5 - 0.25) / 0.5 = 0.5, + // meaning that this color is partially washed out. + // A saturation value of 0 corresponds to a greyscale color, one in which the color is *completely* washed out and there is no actual hue. + saturation = chroma / value; + } + + return Hsv(hue, saturation, value); +} + +MDWMBlurGlassExt::Rgb MDWMBlurGlassExt::HsvToRgb(const MDWMBlurGlassExt::Hsv& hsv) +{ + double hue = hsv.h; + double saturation = hsv.s; + double value = hsv.v; + + // We want the hue to be between 0 and 359, + // so we first ensure that that's the case. + while (hue >= 360.0) + { + hue -= 360.0; + } + + while (hue < 0.0) + { + hue += 360.0; + } + + // We similarly clamp saturation and value between 0 and 1. + saturation = saturation < 0.0 ? 0.0 : saturation; + saturation = saturation > 1.0 ? 1.0 : saturation; + + value = value < 0.0 ? 0.0 : value; + value = value > 1.0 ? 1.0 : value; + + // The first thing that we need to do is to determine the chroma (see above for its definition). + // Remember from above that: + // + // 1. The chroma is the difference between the maximum and the minimum of the RGB channels, + // 2. The value is the maximum of the RGB channels, and + // 3. The saturation comes from dividing the chroma by the maximum of the RGB channels (i.e., the value). + // + // From these facts, you can see that we can retrieve the chroma by simply multiplying the saturation and the value, + // and we can retrieve the minimum of the RGB channels by subtracting the chroma from the value. + const double chroma = saturation * value; + const double min = value - chroma; + + // If the chroma is zero, then we have a greyscale color. In that case, the maximum and the minimum RGB channels + // have the same value (and, indeed, all of the RGB channels are the same), so we can just immediately return + // the minimum value as the value of all the channels. + if (chroma == 0) + { + return MDWMBlurGlassExt::Rgb(min, min, min); + } + + // If the chroma is not zero, then we need to continue. The first step is to figure out + // what section of the color wheel we're located in. In order to do that, we'll divide the hue by 60. + // The resulting value means we're in one of the following locations: + // + // 0 - Between red and yellow. + // 1 - Between yellow and green. + // 2 - Between green and cyan. + // 3 - Between cyan and blue. + // 4 - Between blue and purple. + // 5 - Between purple and red. + // + // In each of these sextants, one of the RGB channels is completely present, one is partially present, and one is not present. + // For example, as we transition between red and yellow, red is completely present, green is becoming increasingly present, and blue is not present. + // Then, as we transition from yellow and green, green is now completely present, red is becoming decreasingly present, and blue is still not present. + // As we transition from green to cyan, green is still completely present, blue is becoming increasingly present, and red is no longer present. And so on. + // + // To convert from hue to RGB value, we first need to figure out which of the three channels is in which configuration + // in the sextant that we're located in. Next, we figure out what value the completely-present color should have. + // We know that chroma = (max - min), and we know that this color is the max color, so to find its value we simply add + // min to chroma to retrieve max. Finally, we consider how far we've transitioned from the pure form of that color + // to the next color (e.g., how far we are from pure red towards yellow), and give a value to the partially present channel + // equal to the minimum plus the chroma (i.e., the max minus the min), multiplied by the percentage towards the new color. + // This gets us a value between the maximum and the minimum representing the partially present channel. + // Finally, the not-present color must be equal to the minimum value, since it is the one least participating in the overall color. + const int sextant = static_cast(hue / 60); + const double intermediateColorPercentage = hue / 60 - sextant; + const double max = chroma + min; + + double r = 0; + double g = 0; + double b = 0; + + switch (sextant) + { + case 0: + r = max; + g = min + chroma * intermediateColorPercentage; + b = min; + break; + case 1: + r = min + chroma * (1 - intermediateColorPercentage); + g = max; + b = min; + break; + case 2: + r = min; + g = max; + b = min + chroma * intermediateColorPercentage; + break; + case 3: + r = min; + g = min + chroma * (1 - intermediateColorPercentage); + b = max; + break; + case 4: + r = min + chroma * intermediateColorPercentage; + g = min; + b = max; + break; + case 5: + r = max; + g = min; + b = min + chroma * (1 - intermediateColorPercentage); + break; + } + + return MDWMBlurGlassExt::Rgb(r, g, b); +} + +MDWMBlurGlassExt::Rgb MDWMBlurGlassExt::HexToRgb(const std::wstring_view& input) +{ + const auto [rgb, a] = HexToRgba(input); + return rgb; +} + +winrt::hstring MDWMBlurGlassExt::RgbToHex(const Rgb& rgb) +{ + const BYTE rByte = static_cast(round(rgb.r * 255.0)); + const BYTE gByte = static_cast(round(rgb.g * 255.0)); + const BYTE bByte = static_cast(round(rgb.b * 255.0)); + + const unsigned long hexValue = (rByte << 16) + (gByte << 8) + bByte; + + // We'll size this string to accommodate "#XXXXXX" - i.e., a full RGB number with a # sign. + wchar_t hexString[8]; + winrt::check_hresult(StringCchPrintfW(&hexString[0], 8, L"#%06X", hexValue)); + return winrt::hstring(hexString); +} + +std::tuple MDWMBlurGlassExt::HexToRgba(const std::wstring_view& input) +{ + // The input always begins with a #, so we'll move past that. + auto ptr = input.data(); + ++ptr; + + const auto hexValue = TryParseInt(ptr, 16); + + // If we failed to parse the string into an integer, then we'll return all -1's. + // ARGB values can never be negative, so this is a convenient error state to use + // to indicate that this value should not actually be used. + if (!hexValue.has_value()) + { + return { Rgb(-1, -1, -1), -1 }; + } + + const auto hex = hexValue.value(); + const BYTE a = static_cast((hex & 0xff000000) >> 24); + const BYTE r = static_cast((hex & 0x00ff0000) >> 16); + const BYTE g = static_cast((hex & 0x0000ff00) >> 8); + const BYTE b = static_cast(hex & 0x000000ff); + + return { Rgb(r / 255.0, g / 255.0, b / 255.0), a / 255.0 }; +} + +winrt::hstring MDWMBlurGlassExt::RgbaToHex(const MDWMBlurGlassExt::Rgb& rgb, double alpha) +{ + const BYTE aByte = static_cast(round(alpha * 255.0)); + const BYTE rByte = static_cast(round(rgb.r * 255.0)); + const BYTE gByte = static_cast(round(rgb.g * 255.0)); + const BYTE bByte = static_cast(round(rgb.b * 255.0)); + + const unsigned long hexValue = (aByte << 24) + (rByte << 16) + (gByte << 8) + (bByte & 0xff); + + // We'll size this string to accommodate "#XXXXXXXX" - i.e., a full ARGB number with a # sign. + wchar_t hexString[10]; + winrt::check_hresult(StringCchPrintfW(&hexString[0], 10, L"#%08X", hexValue)); + return winrt::hstring(hexString); +} + +winrt::Windows::UI::Color MDWMBlurGlassExt::ColorFromRgba(const MDWMBlurGlassExt::Rgb& rgb, double alpha) +{ + return winrt::Windows::UI::ColorHelper::FromArgb( + static_cast(round(alpha * 255)), + static_cast(round(rgb.r * 255)), + static_cast(round(rgb.g * 255)), + static_cast(round(rgb.b * 255))); +} + +MDWMBlurGlassExt::Rgb MDWMBlurGlassExt::RgbFromColor(const winrt::Windows::UI::Color& color) +{ + return Rgb(color.R / 255.0, color.G / 255.0, color.B / 255.0); +} diff --git a/DWMBlurGlassExt/Common/ColorConversion.hpp b/DWMBlurGlassExt/Common/ColorConversion.hpp new file mode 100644 index 0000000..bcdc8f1 --- /dev/null +++ b/DWMBlurGlassExt/Common/ColorConversion.hpp @@ -0,0 +1,56 @@ +#pragma once +#include "winrt_impl.h" + +namespace MDWMBlurGlassExt +{ + // Helper classes used for converting between RGB, HSV, and hex. + class Rgb + { + public: + double r{}; + double g{}; + double b{}; + Rgb() = default; + Rgb(double r, double g, double b); + }; + + class Hsv + { + public: + double h{}; + double s{}; + double v{}; + Hsv() = default; + Hsv(double h, double s, double v); + }; + + std::optional TryParseInt(const std::wstring_view& s); + std::optional TryParseInt(const std::wstring_view& str, int base); + + Hsv RgbToHsv(const Rgb& rgb); + Rgb HsvToRgb(const Hsv& hsv); + + Rgb HexToRgb(const std::wstring_view& input); + winrt::hstring RgbToHex(const Rgb& rgb); + + std::tuple HexToRgba(const std::wstring_view& input); + winrt::hstring RgbaToHex(const Rgb& rgb, double alpha); + + winrt::Windows::UI::Color ColorFromRgba(const Rgb& rgb, double alpha = 1.0); + Rgb RgbFromColor(const winrt::Windows::UI::Color& color); + + // We represent HSV and alpha using a Vector4 (float4 in C++/WinRT). + // We'll use the following helper methods to convert between the four dimensions and HSVA. + namespace hsv + { + inline float GetHue(const winrt::Windows::Foundation::Numerics::float4& hsva) { return hsva.x; } + inline void SetHue(winrt::Windows::Foundation::Numerics::float4& hsva, float hue) { hsva.x = hue; } + inline float GetSaturation(const winrt::Windows::Foundation::Numerics::float4& hsva) { return hsva.y; } + inline void SetSaturation(winrt::Windows::Foundation::Numerics::float4& hsva, float saturation) { hsva.y = saturation; } + inline float GetValue(const winrt::Windows::Foundation::Numerics::float4& hsva) { return hsva.z; } + inline void SetValue(winrt::Windows::Foundation::Numerics::float4& hsva, float value) { hsva.z = value; } + inline float GetAlpha(const winrt::Windows::Foundation::Numerics::float4& hsva) { return hsva.w; } + inline void SetAlpha(winrt::Windows::Foundation::Numerics::float4& hsva, float alpha) { hsva.w = alpha; } + } + +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Common/DWMStruct.cpp b/DWMBlurGlassExt/Common/DWMStruct.cpp index 9cbf05e..04a93e9 100644 --- a/DWMBlurGlassExt/Common/DWMStruct.cpp +++ b/DWMBlurGlassExt/Common/DWMStruct.cpp @@ -63,6 +63,20 @@ namespace MDWMBlurGlassExt::DWM const HWND hWnd = *((HWND*)this + 5); return hWnd; } + CTopLevelWindow* CWindowData::GetWindow() const + { + CTopLevelWindow* window{ nullptr }; + + if (os::buildNumber < 22000) + { + window = reinterpret_cast(this)[48]; + } + else + { + window = reinterpret_cast(this)[55]; + } + return window; + } bool CWindowData::IsUsingDarkMode() const { @@ -168,6 +182,35 @@ namespace MDWMBlurGlassExt::DWM return reinterpret_cast(reinterpret_cast(this)[2]); } + bool CVisual::IsCloneAllowed() const + { + const BYTE* properties{ nullptr }; + + if (os::buildNumber < 22000) + { + properties = &reinterpret_cast(this)[84]; + } + else if (os::buildNumber < 22621) + { + properties = &reinterpret_cast(this)[92]; + } + else if (os::buildNumber < 26020) + { + properties = &reinterpret_cast(this)[92]; + } + else + { + properties = &reinterpret_cast(this)[36]; + } + + bool allowed{ false }; + if (properties) + { + allowed = (*properties & 8) == 0; + } + + return allowed; + } bool CVisual::AllowVisualTreeClone(bool allow) { BYTE* properties; @@ -205,6 +248,19 @@ namespace MDWMBlurGlassExt::DWM return allowed; } + void CVisual::Cloak(bool cloak) + { + if (!cloak) + { + SetOpacity(1.); + UpdateOpacity(); + } + else + { + SetOpacity(0.); + UpdateOpacity(); + } + } void CVisual::SetInsetFromParent(MARGINS* margins) { @@ -250,6 +306,10 @@ namespace MDWMBlurGlassExt::DWM { DEFCALL_MHOST_METHOD(CVisual::SetOpacity, opacity); } + HRESULT STDMETHODCALLTYPE CVisual::UpdateOpacity() + { + return DEFCALL_MHOST_METHOD(CVisual::UpdateOpacity, ); + } void CVisual::SetScale(double x, double y) { @@ -296,24 +356,6 @@ namespace MDWMBlurGlassExt::DWM return DEFCALL_MHOST_METHOD(CVisual::Initialize); } - void CVisual::Show(bool show) - { - if (show) - { - //this->Unhide(); - this->SetOpacity(1.); - this->SendSetOpacity(1.); - //this->ConnectToParent(true); - } - else - { - //this->Hide(); - this->SetOpacity(0.); - this->SendSetOpacity(0.); - //this->ConnectToParent(false); - } - } - HRESULT VisualCollection::RemoveAll() { return DEFCALL_MHOST_METHOD(VisualCollection::RemoveAll); @@ -385,158 +427,191 @@ namespace MDWMBlurGlassExt::DWM return visual; } - CVisual* CTopLevelWindow::GetNCAreaBackgroundVisual() const + CAccent* CTopLevelWindow::GetAccent() const { - const auto visual = *(CVisual**)((char*)this + 288); - return visual; + CAccent* accent{ nullptr }; + + if (os::buildNumber < 22000) + { + accent = reinterpret_cast(this)[34]; + } + else if (os::buildNumber < 22621) + { + accent = reinterpret_cast(this)[35]; + } + else if (os::buildNumber < 26020) + { + accent = reinterpret_cast(this)[37]; + } + else + { + accent = reinterpret_cast(this)[34]; + } + + return accent; } + CVisual* CTopLevelWindow::GetLegacyVisual() const + { + CVisual* visual{ nullptr }; + if (os::buildNumber < 22000) + { + visual = reinterpret_cast(this)[36]; + } + else if (os::buildNumber < 22621) + { + visual = reinterpret_cast(this)[37]; + } + else if (os::buildNumber < 26020) + { + visual = reinterpret_cast(this)[39]; + } + else + { + visual = reinterpret_cast(this)[40]; + } + + return visual; + } CVisual* CTopLevelWindow::GetClientBlurVisual() const { - const auto visual = (CVisual*)*((DWORD64*)this + 34); + CVisual* visual{ nullptr }; + + if (os::buildNumber < 22000) + { + visual = reinterpret_cast(this)[37]; + } + else if (os::buildNumber < 22621) + { + visual = reinterpret_cast(this)[39]; + } + else if (os::buildNumber < 26020) + { + visual = reinterpret_cast(this)[37]; + } + else + { + visual = reinterpret_cast(this)[40]; + } + return visual; } - - std::vector> CTopLevelWindow::GetNCBackgroundVisualList() const + CVisual* CTopLevelWindow::GetSystemBackdropVisual() const { - std::vector> visuals{}; + CVisual* visual{ nullptr }; - if (os::buildNumber < 19041) + if (os::buildNumber < 22000) { - // TO-DO } - else if (os::buildNumber < 22000) + else if (os::buildNumber < 22621) + { + visual = reinterpret_cast(this)[38]; + } + else if (os::buildNumber < 26020) + { + visual = reinterpret_cast(this)[40]; + } + else + { + visual = reinterpret_cast(this)[35]; + } + + return visual; + } + CVisual* CTopLevelWindow::GetAccentColorVisual() const + { + CVisual* visual{ nullptr }; + + if (os::buildNumber < 22000) { - if (reinterpret_cast(this)[34]) // accent - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[34]); - } - //if (reinterpret_cast(this)[36]) // legacy - //{ - // visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[36]); - //} - if (reinterpret_cast(this)[37]) // client blur - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[37]); - } } else if (os::buildNumber < 22621) { - if (reinterpret_cast(this)[35]) // accent - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[35]); - } - //if (reinterpret_cast(this)[37]) // legacy - //{ - // visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[37]); - //} - if (reinterpret_cast(this)[38]) // system backdrop - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[38]); - } - if (reinterpret_cast(this)[39]) // client blur - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[39]); - } } else if (os::buildNumber < 26020) { - if (reinterpret_cast(this)[37]) // accent - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[37]); - } - //if (reinterpret_cast(this)[39]) // legacy - //{ - // visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[39]); - //} - if (reinterpret_cast(this)[40]) // system backdrop - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[40]); - } - if (reinterpret_cast(this)[41]) // accent color - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[41]); - } - if (reinterpret_cast(this)[42]) // client blur - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[42]); - } + visual = reinterpret_cast(this)[41]; } else { - //if (reinterpret_cast(this)[32]) // legacy - //{ - // visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[32]); - //} - if (reinterpret_cast(this)[34]) // accent - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[34]); - } - if (reinterpret_cast(this)[35]) // system backdrop - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[35]); - } - if (reinterpret_cast(this)[36]) // accent color - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[36]); - } - if (reinterpret_cast(this)[37]) // client blur - { - visuals.emplace_back(nullptr).copy_from(reinterpret_cast(this)[37]); - } + visual = reinterpret_cast(this)[36]; } - if (os::buildNumber >= 22000) + + return visual; + } + std::vector> CTopLevelWindow::GetNCBackgroundVisuals() const + { + std::vector> visuals{}; + + if (GetLegacyVisual()) { - auto legacySolidColorVisual{ GetNCLegacySolidColorVisual() }; - if (legacySolidColorVisual) - { - visuals.emplace_back(nullptr).copy_from(legacySolidColorVisual); - } + visuals.emplace_back(nullptr).copy_from(GetLegacyVisual()); + } + if (GetAccent()) + { + visuals.emplace_back(nullptr).copy_from(GetAccent()); + } + if (GetClientBlurVisual()) + { + visuals.emplace_back(nullptr).copy_from(GetClientBlurVisual()); + } + if (GetSystemBackdropVisual()) + { + visuals.emplace_back(nullptr).copy_from(GetSystemBackdropVisual()); + } + if (GetAccentColorVisual()) + { + visuals.emplace_back(nullptr).copy_from(GetAccentColorVisual()); } return visuals; } - CVisual* CTopLevelWindow::GetNCLegacySolidColorVisual() const + bool CTopLevelWindow::IsNCBackgroundVisualsCloneAllAllowed() { - CVisual* visual{nullptr}; - - if (os::buildNumber < 22000) + for (const auto& visual : GetNCBackgroundVisuals()) { - if (reinterpret_cast(this)[36]) // legacy + if (!visual->IsCloneAllowed()) { - visual = reinterpret_cast(this)[36]; + return false; } } + + return true; + } + CSolidColorLegacyMilBrushProxy* const* CTopLevelWindow::GetBorderMilBrush() const + { + CSolidColorLegacyMilBrushProxy* const* brush{ nullptr }; + + if (os::buildNumber < 19041) + { + // TO-DO + } + else if (os::buildNumber < 22000) + { + brush = &reinterpret_cast(this)[94]; + } else if (os::buildNumber < 22621) { - if (reinterpret_cast(this)[37]) // legacy - { - visual = reinterpret_cast(this)[37]; - } + brush = &reinterpret_cast(this)[98]; } else if (os::buildNumber < 26020) { - if (reinterpret_cast(this)[39]) // legacy + auto legacyBackgroundVisual{ reinterpret_cast(this)[39] }; + if (legacyBackgroundVisual) { - visual = reinterpret_cast(this)[39]; + brush = &reinterpret_cast(legacyBackgroundVisual)[38]; } } else { - if (reinterpret_cast(this)[32]) // legacy + auto legacyBackgroundVisual{ reinterpret_cast(this)[34] }; + if (legacyBackgroundVisual) { - visual = reinterpret_cast(this)[32]; + brush = &reinterpret_cast(legacyBackgroundVisual)[32]; } } - return visual; - } - void CTopLevelWindow::ShowNCBackgroundVisualList(bool show) - { - for (auto visual : GetNCBackgroundVisualList()) - { - visual->Show(show); - } + return brush; } CRgnGeometryProxy* const& CTopLevelWindow::GetBorderGeometry() const @@ -762,6 +837,48 @@ namespace MDWMBlurGlassExt::DWM static auto pfun = MHostGetProcAddress("CAccent::s_IsPolicyActive"); return pfun(accentPolicy); } + CBaseGeometryProxy* const& CAccent::GetClipGeometry() const + { + CBaseGeometryProxy* const* geometry{ nullptr }; + + if (os::buildNumber < 22000) + { + geometry = &reinterpret_cast(this)[52]; + } + else if (os::buildNumber < 22621) + { + geometry = &reinterpret_cast(this)[53]; + } + else if (os::buildNumber < 26020) + { + geometry = &reinterpret_cast(this)[48]; + } + else + { + geometry = &reinterpret_cast(this)[42]; + } + + return *geometry; + } + + HRESULT STDMETHODCALLTYPE CDrawGeometryInstruction::Create(CBaseLegacyMilBrushProxy* brush, CBaseGeometryProxy* geometry, CDrawGeometryInstruction** instruction) + { + static auto pfun = MHostGetProcAddress("CDrawGeometryInstruction::Create"); + return pfun(brush, geometry, instruction); + } + HRESULT STDMETHODCALLTYPE CRenderDataVisual::AddInstruction(CRenderDataInstruction* instruction) + { + return DEFCALL_MHOST_METHOD(CRenderDataVisual::AddInstruction, instruction); + } + HRESULT STDMETHODCALLTYPE CRenderDataVisual::ClearInstructions() + { + return DEFCALL_MHOST_METHOD(CRenderDataVisual::ClearInstructions, ); + } + HRESULT STDMETHODCALLTYPE CCanvasVisual::Create(CCanvasVisual** visual) + { + static auto pfun = MHostGetProcAddress("CCanvasVisual::Create"); + return pfun(visual); + } POINT* CButton::GetPoint() { @@ -933,5 +1050,9 @@ namespace MDWMBlurGlassExt::DWM { return DEFCALL_MHOST_METHOD(CWindowList::GetSyncedWindowData, dwmWindow, shared, pWindowData); } + HRESULT STDMETHODCALLTYPE CWindowList::GetSyncedWindowDataByHwnd(HWND hwnd, CWindowData** windowData) + { + return DEFCALL_MHOST_METHOD(CWindowList::GetSyncedWindowDataByHwnd, hwnd, windowData); + } } #pragma pop_macro("DEFCALL_MHOST_METHOD") \ No newline at end of file diff --git a/DWMBlurGlassExt/Common/DWMStruct.h b/DWMBlurGlassExt/Common/DWMStruct.h index 75eaf2f..dd3831e 100644 --- a/DWMBlurGlassExt/Common/DWMStruct.h +++ b/DWMBlurGlassExt/Common/DWMStruct.h @@ -50,7 +50,8 @@ namespace MDWMBlurGlassExt::DWM virtual ~CBaseObject() = default; }; - struct CSolidColorLegacyMilBrushProxy {}; + struct CBaseLegacyMilBrushProxy : CBaseObject {}; + struct CSolidColorLegacyMilBrushProxy : CBaseLegacyMilBrushProxy {}; struct CDrawingContext {}; struct CDrawListEntryBuilder {}; struct MilRectF @@ -78,11 +79,18 @@ namespace MDWMBlurGlassExt::DWM int32_t nFlags; uint32_t nColor; int32_t nAnimationId; + + inline bool IsAccentBlurEnabled() const + { + return (DWORD)nAccentState > 2 && (DWORD)nAccentState < 5; + } }; + struct CTopLevelWindow; struct CWindowData : CBaseObject { HWND GetHWND() const; + CTopLevelWindow* GetWindow() const; bool IsUsingDarkMode() const; DWORD GetNonClientAttribute() const; bool IsImmersiveWindow() const; @@ -123,7 +131,9 @@ namespace MDWMBlurGlassExt::DWM CVisualProxy* GetVisualProxy() const; + bool IsCloneAllowed() const; bool AllowVisualTreeClone(bool allow); + void Cloak(bool cloak); void SetInsetFromParent(MARGINS* margins); @@ -142,6 +152,7 @@ namespace MDWMBlurGlassExt::DWM void ConnectToParent(bool connect); void SetOpacity(double opacity); + HRESULT STDMETHODCALLTYPE UpdateOpacity(); void SetScale(double x, double y); @@ -158,8 +169,6 @@ namespace MDWMBlurGlassExt::DWM HRESULT MoveToFront(bool unknown); HRESULT Initialize(); - - void Show(bool show); }; struct CContainerVisual : CBaseObject @@ -194,6 +203,7 @@ namespace MDWMBlurGlassExt::DWM { HRESULT GetExtendedFrameBounds(HWND hWnd, RECT* rect); HRESULT GetSyncedWindowData(IDwmWindow* dwmWindow, bool shared, CWindowData** pWindowData); + HRESULT STDMETHODCALLTYPE GetSyncedWindowDataByHwnd(HWND hwnd, CWindowData** windowData); }; struct CTopLevelWindow : CVisual @@ -203,11 +213,15 @@ namespace MDWMBlurGlassExt::DWM CWindowData* GetData(); VisualCollection* GetNCAreaVisualCollection(); CVisual* GetVisual() const; - CVisual* GetNCAreaBackgroundVisual() const; + + struct CAccent* GetAccent() const; + CVisual* GetLegacyVisual() const; CVisual* GetClientBlurVisual() const; - std::vector> GetNCBackgroundVisualList() const; - CVisual* GetNCLegacySolidColorVisual() const; - void ShowNCBackgroundVisualList(bool show); + CVisual* GetSystemBackdropVisual() const; + CVisual* GetAccentColorVisual() const; + std::vector> GetNCBackgroundVisuals() const; + bool IsNCBackgroundVisualsCloneAllAllowed(); + CSolidColorLegacyMilBrushProxy* const* GetBorderMilBrush() const; CRgnGeometryProxy* const& GetBorderGeometry() const; CRgnGeometryProxy* const& GetTitlebarGeometry() const; @@ -243,9 +257,44 @@ namespace MDWMBlurGlassExt::DWM ID2D1Effect* DirBlurKernelYEffect(); }; - struct CAccent + struct CAccent : CVisual { static bool s_IsPolicyActive(const ACCENT_POLICY* accentPolicy); + CBaseGeometryProxy* const& GetClipGeometry() const; + }; + + struct IRenderDataBuilder : IUnknown + { + STDMETHOD(DrawBitmap)(UINT bitmapHandleTableIndex) PURE; + STDMETHOD(DrawGeometry)(UINT geometryHandleTableIndex, UINT brushHandleTableIndex) PURE; + STDMETHOD(DrawImage)(const D2D1_RECT_F& rect, UINT imageHandleTableIndex) PURE; + STDMETHOD(DrawMesh2D)(UINT meshHandleTableIndex, UINT brushHandleTableIndex) PURE; + STDMETHOD(DrawRectangle)(const D2D1_RECT_F* rect, UINT brushHandleTableIndex) PURE; + STDMETHOD(DrawTileImage)(UINT imageHandleTableIndex, const D2D1_RECT_F& rect, float opacity, const D2D1_POINT_2F& point) PURE; + STDMETHOD(DrawVisual)(UINT visualHandleTableIndex) PURE; + STDMETHOD(Pop)() PURE; + STDMETHOD(PushTransform)(UINT transformHandleTableInfex) PURE; + STDMETHOD(DrawSolidRectangle)(const D2D1_RECT_F& rect, const D2D1_COLOR_F& color) PURE; + }; + struct CRenderDataInstruction : CBaseObject + { + STDMETHOD(WriteInstruction)( + IRenderDataBuilder* builder, + const struct CVisual* visual + ) PURE; + }; + struct CDrawGeometryInstruction : CRenderDataInstruction + { + static HRESULT STDMETHODCALLTYPE Create(CBaseLegacyMilBrushProxy* brush, CBaseGeometryProxy* geometry, CDrawGeometryInstruction** instruction); + }; + struct CRenderDataVisual : CVisual + { + HRESULT STDMETHODCALLTYPE AddInstruction(CRenderDataInstruction* instruction); + HRESULT STDMETHODCALLTYPE ClearInstructions(); + }; + struct CCanvasVisual : CRenderDataVisual + { + static HRESULT STDMETHODCALLTYPE Create(CCanvasVisual** visual); }; struct COcclusionContext {}; @@ -261,6 +310,10 @@ namespace MDWMBlurGlassExt::DWM { inline static CDesktopManager* s_pDesktopManagerInstance{ nullptr }; + bool IsVanillaTheme() const + { + return reinterpret_cast(this)[25]; + } CWindowList* GetWindowList() const; IWICImagingFactory2* GetWICFactory() const; @@ -337,4 +390,42 @@ namespace MDWMBlurGlassExt::DWM { static HRESULT CreateGeometryFromHRGN(HRGN hrgn, CRgnGeometryProxy** geometry); }; + + struct CSecondaryWindowRepresentation + { + CWindowData* GetWindowData() const + { + return reinterpret_cast(this)[8]; + } + CWindowData* GetOwnedWindowData() const + { + return reinterpret_cast(this)[4]; + } + CVisual* GetCachedVisual() const + { + return reinterpret_cast(this)[6]; + } + CVisual* GetVisual() const + { + return reinterpret_cast(this)[7]; + } + POINT GetOffset() const + { + return + { + *(reinterpret_cast(this) + 22), + *(reinterpret_cast(this) + 24) + }; + } + RECT GetRect() const + { + return + { + *(reinterpret_cast(this) + 23), + *(reinterpret_cast(this) + 25), + *(reinterpret_cast(this) + 20), + *(reinterpret_cast(this) + 21) + }; + } + }; } \ No newline at end of file diff --git a/DWMBlurGlassExt/Common/DefFunctionList.h b/DWMBlurGlassExt/Common/DefFunctionList.h index 05ff058..363b631 100644 --- a/DWMBlurGlassExt/Common/DefFunctionList.h +++ b/DWMBlurGlassExt/Common/DefFunctionList.h @@ -37,6 +37,8 @@ namespace MDWMBlurGlassExt { udwm, "CSolidColorLegacyMilBrushProxy::Update" }, { udwm, "CWindowList::GetExtendedFrameBounds" }, + { udwm, "CWindowList::UpdateAccentBlurRect" }, + { udwm, "CWindowList::GetSyncedWindowDataByHwnd" }, { udwm, "ResourceHelper::CreateGeometryFromHRGN" }, { udwm, "HrgnFromRects" }, @@ -54,6 +56,7 @@ namespace MDWMBlurGlassExt { udwm, "CTopLevelWindow::InitializeVisualTreeClone" }, { udwm, "CTopLevelWindow::UpdateNCAreaBackground" }, { udwm, "CTopLevelWindow::OnAccentPolicyUpdated" }, + { udwm, "CTopLevelWindow::OnClipUpdated" }, { udwm, "CTopLevelWindow::~CTopLevelWindow" }, { udwm, "CGlassColorizationParameters::AdjustWindowColorization" }, @@ -87,6 +90,7 @@ namespace MDWMBlurGlassExt { udwm, "CVisual::Hide" }, { udwm, "CVisual::ConnectToParent" }, { udwm, "CVisual::SetOpacity" }, + { udwm, "CVisual::UpdateOpacity" }, { udwm, "CVisual::SetScale" }, { udwm, "CVisual::SendSetOpacity" }, { udwm, "CVisual::RenderRecursive" }, @@ -99,6 +103,11 @@ namespace MDWMBlurGlassExt { udwm, "CContainerVisual" }, { udwm, "CContainerVisual::Create" }, + { udwm, "CRenderDataVisual::AddInstruction" }, + { udwm, "CRenderDataVisual::ClearInstructions" }, + { udwm, "CDrawGeometryInstruction::Create" }, + { udwm, "CCanvasVisual::Create" }, + { udwm, "CWindowData::IsImmersiveWindow" }, { udwm, "CMatrixTransformProxy::Update" } diff --git a/DWMBlurGlassExt/DWMBlurGlass.cpp b/DWMBlurGlassExt/DWMBlurGlass.cpp index 076c3e6..fd2001a 100644 --- a/DWMBlurGlassExt/DWMBlurGlass.cpp +++ b/DWMBlurGlassExt/DWMBlurGlass.cpp @@ -116,6 +116,8 @@ namespace MDWMBlurGlassExt WriteIAT(udwmModule, "gdi32.dll", { { "CreateRoundRectRgn", g_funCreateRoundRgn } }); g_startup = false; + + PostMessageW(FindWindowW(L"Dwm", nullptr), WM_THEMECHANGED, 0, 0); } void Refresh() @@ -132,6 +134,8 @@ namespace MDWMBlurGlassExt AccentBlur::Refresh(); BlurRadiusTweaker::Refresh(); CustomButton::Refresh(); + + PostMessageW(FindWindowW(L"Dwm", nullptr), WM_THEMECHANGED, 0, 0); } namespace Common diff --git a/DWMBlurGlassExt/DWMBlurGlassExt.rc b/DWMBlurGlassExt/DWMBlurGlassExt.rc index 09f235a..7371149 100644 Binary files a/DWMBlurGlassExt/DWMBlurGlassExt.rc and b/DWMBlurGlassExt/DWMBlurGlassExt.rc differ diff --git a/DWMBlurGlassExt/DWMBlurGlassExt.vcxproj b/DWMBlurGlassExt/DWMBlurGlassExt.vcxproj index 63228e5..ac4f288 100644 --- a/DWMBlurGlassExt/DWMBlurGlassExt.vcxproj +++ b/DWMBlurGlassExt/DWMBlurGlassExt.vcxproj @@ -162,6 +162,14 @@ + + + + + + + + @@ -192,14 +200,16 @@ - + + + @@ -212,7 +222,6 @@ - diff --git a/DWMBlurGlassExt/DWMBlurGlassExt.vcxproj.filters b/DWMBlurGlassExt/DWMBlurGlassExt.vcxproj.filters index 7d574f3..4cde1c1 100644 --- a/DWMBlurGlassExt/DWMBlurGlassExt.vcxproj.filters +++ b/DWMBlurGlassExt/DWMBlurGlassExt.vcxproj.filters @@ -40,6 +40,9 @@ {d88a7a1e-9bb4-490f-b555-75ad09fbd934} + + {84028c5e-ea88-4c4c-8025-bcd2770a0c2a} + @@ -141,15 +144,42 @@ 头文件\Common - - 头文件\Section - 头文件\Section 头文件\Section + + 头文件\Backdrops + + + 头文件\Backdrops + + + 头文件\Backdrops + + + 头文件\Backdrops + + + 头文件\Backdrops + + + 头文件\Backdrops + + + 头文件\Common + + + 头文件\Backdrops + + + 头文件\Section + + + 头文件\Section + @@ -197,15 +227,15 @@ 源文件\Section - - 源文件\Section - 源文件\Section 源文件\Section + + 源文件\Common + diff --git a/DWMBlurGlassExt/Effects/BlendEffect.hpp b/DWMBlurGlassExt/Effects/BlendEffect.hpp index 003ed4d..5a70e67 100644 --- a/DWMBlurGlassExt/Effects/BlendEffect.hpp +++ b/DWMBlurGlassExt/Effects/BlendEffect.hpp @@ -16,30 +16,22 @@ namespace MDWMBlurGlassExt { SetProperty(D2D1_BLEND_PROP_MODE, BoxValue(blendMode)); } - void SetBackground(ABI::Windows::Graphics::Effects::IGraphicsEffectSource* source) + void SetBackground(const winrt::Windows::Graphics::Effects::IGraphicsEffectSource& source) { SetInput(0, source); } - void SetBackground(const winrt::com_ptr source) - { - SetInput(0, source.get()); - } void SetBackground(const winrt::Windows::UI::Composition::CompositionEffectSourceParameter& source) { - SetInput(0, source.as().get()); + SetInput(0, source); } - void SetForeground(ABI::Windows::Graphics::Effects::IGraphicsEffectSource* source) + void SetForeground(const winrt::Windows::Graphics::Effects::IGraphicsEffectSource& source) { SetInput(1, source); } - void SetForeground(const winrt::com_ptr source) - { - SetInput(1, source.get()); - } void SetForeground(const winrt::Windows::UI::Composition::CompositionEffectSourceParameter& source) { - SetInput(1, source.as().get()); + SetInput(1, source); } }; } \ No newline at end of file diff --git a/DWMBlurGlassExt/Effects/BorderEffect.hpp b/DWMBlurGlassExt/Effects/BorderEffect.hpp index 273e0ca..d53b971 100644 --- a/DWMBlurGlassExt/Effects/BorderEffect.hpp +++ b/DWMBlurGlassExt/Effects/BorderEffect.hpp @@ -15,11 +15,11 @@ namespace MDWMBlurGlassExt void SetExtendX(D2D1_BORDER_EDGE_MODE extendX = D2D1_BORDER_EDGE_MODE_CLAMP) { - SetProperty(D2D1_BORDER_PROP_EDGE_MODE_X, BoxValue(extendX)); + SetProperty(D2D1_BORDER_PROP_EDGE_MODE_X, BoxValue(extendX)); } void SetExtendY(D2D1_BORDER_EDGE_MODE extendY = D2D1_BORDER_EDGE_MODE_CLAMP) { - SetProperty(D2D1_BORDER_PROP_EDGE_MODE_Y, BoxValue(extendY)); + SetProperty(D2D1_BORDER_PROP_EDGE_MODE_Y, BoxValue(extendY)); } }; } \ No newline at end of file diff --git a/DWMBlurGlassExt/Effects/BrightnessEffect.hpp b/DWMBlurGlassExt/Effects/BrightnessEffect.hpp new file mode 100644 index 0000000..aad2a59 --- /dev/null +++ b/DWMBlurGlassExt/Effects/BrightnessEffect.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "ColorMatrixEffect.hpp" + +namespace AcrylicEverywhere +{ + class BrightnessEffect : public ColorMatrixEffect + { + public: + BrightnessEffect() : ColorMatrixEffect{} + { + SetBrightnessAmount(); + } + virtual ~BrightnessEffect() = default; + + void SetBrightnessAmount(float r = 1.f, float g = 1.f, float b = 1.f) + { + SetColorMatrix( + D2D1::Matrix5x4F{ + r, 0.f, 0.f, 0.f, + 0.f, g, 0.f, 0.f, + 0.f, 0.f, b, 0.f, + 0.f, 0.f, 0.f, 1.f, + 0.f, 0.f, 0.f, 0.f + } + ); + } + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Effects/CanvasEffect.hpp b/DWMBlurGlassExt/Effects/CanvasEffect.hpp index 353f166..cba7d3b 100644 --- a/DWMBlurGlassExt/Effects/CanvasEffect.hpp +++ b/DWMBlurGlassExt/Effects/CanvasEffect.hpp @@ -8,30 +8,30 @@ namespace MDWMBlurGlassExt { struct NamedProperty { - const wchar_t* Name; // Compile-time constant + LPCWSTR Name; // Compile-time constant UINT Index; // Property index using GRAPHICS_EFFECT_PROPERTY_MAPPING = ABI::Windows::Graphics::Effects::GRAPHICS_EFFECT_PROPERTY_MAPPING; GRAPHICS_EFFECT_PROPERTY_MAPPING Mapping; }; - class CanvasEffect : public winrt::implements + class CanvasEffect : public winrt::implements { CLSID m_effectId{}; - wil::unique_hstring m_name{}; + winrt::hstring m_name{}; std::unordered_map m_properties{}; - std::unordered_map> m_effectSources{}; + std::unordered_map m_effectSources{}; protected: std::vector m_namedProperties{}; public: CanvasEffect(REFCLSID effectId) : m_effectId{ effectId } {} virtual ~CanvasEffect() = default; - IFACEMETHOD(get_Name)(HSTRING* name) override + winrt::hstring Name() { - return WindowsDuplicateString(m_name.get(), name); + return m_name; } - IFACEMETHOD(put_Name)(HSTRING name) override + void Name(const winrt::hstring& string) { - return WindowsDuplicateString(name, m_name.put()); + m_name = string; } IFACEMETHOD(GetEffectId)(CLSID* id) override @@ -54,14 +54,14 @@ namespace MDWMBlurGlassExt return E_POINTER; } - IFACEMETHOD(GetSource)(UINT index, IGraphicsEffectSource** source) + IFACEMETHOD(GetSource)(UINT index, ABI::Windows::Graphics::Effects::IGraphicsEffectSource** source) { if (!source) { return E_POINTER; } - m_effectSources.at(index).copy_to(source); + m_effectSources.at(index).as().copy_to(source); return S_OK; } IFACEMETHOD(GetPropertyCount)(UINT* count) override @@ -107,41 +107,27 @@ namespace MDWMBlurGlassExt return to; }; - void SetName(const winrt::hstring& name) + void SetName(const winrt::hstring& name) { Name(name); } + void SetInput(UINT index, const winrt::Windows::Graphics::Effects::IGraphicsEffectSource& source) { - put_Name(reinterpret_cast(winrt::get_abi(name))); + m_effectSources.insert_or_assign(index, source); } - void SetInput(UINT index, IGraphicsEffectSource* source) - { - m_effectSources.insert_or_assign(index, construct_from_abi(source)); - } - void SetInput(IGraphicsEffectSource* source) + void SetInput(const winrt::Windows::Graphics::Effects::IGraphicsEffectSource& source) { SetInput(0, source); } - void SetInput(const winrt::com_ptr& source) - { - SetInput(0, source.get()); - } void SetInput(const winrt::Windows::UI::Composition::CompositionEffectSourceParameter& source) { - SetInput(0, source.as().get()); + SetInput(0, source.as()); } - void SetInput(const std::vector& effectSourceList) + void SetInput(const std::vector& effectSourceList) { for (UINT i = 0; i < effectSourceList.size(); i++) { SetInput(i, effectSourceList[i]); } } - void SetInput(const std::vector>& effectSourceList) - { - for (UINT i = 0; i < effectSourceList.size(); i++) - { - SetInput(i, effectSourceList[i].get()); - } - } protected: void SetProperty(UINT index, const winrt::Windows::Foundation::IPropertyValue& value) { @@ -164,6 +150,10 @@ namespace MDWMBlurGlassExt { return winrt::Windows::Foundation::PropertyValue::CreateUInt32(value).as(); } + auto BoxValue(const D2D1_MATRIX_5X4_F& value) + { + return winrt::Windows::Foundation::PropertyValue::CreateSingleArray(value.m[0]).as(); + } template auto BoxValue(float(&value)[size]) { diff --git a/DWMBlurGlassExt/Effects/ColorMatrixEffect.hpp b/DWMBlurGlassExt/Effects/ColorMatrixEffect.hpp new file mode 100644 index 0000000..af9f5bf --- /dev/null +++ b/DWMBlurGlassExt/Effects/ColorMatrixEffect.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "CanvasEffect.hpp" + +namespace AcrylicEverywhere +{ + class ColorMatrixEffect : public CanvasEffect + { + public: + ColorMatrixEffect() : CanvasEffect{ CLSID_D2D1ColorMatrix } + { + SetAlphaMode(); + } + virtual ~ColorMatrixEffect() = default; + + void SetColorMatrix(const D2D1_MATRIX_5X4_F& colorMatrix) + { + SetProperty(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, BoxValue(colorMatrix)); + } + void SetAlphaMode(D2D1_COLORMATRIX_ALPHA_MODE alphaMode = D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED) + { + SetProperty(D2D1_COLORMATRIX_PROP_ALPHA_MODE, BoxValue(alphaMode)); + } + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Effects/ColorSourceEffect.hpp b/DWMBlurGlassExt/Effects/ColorSourceEffect.hpp index 77e8da1..e579985 100644 --- a/DWMBlurGlassExt/Effects/ColorSourceEffect.hpp +++ b/DWMBlurGlassExt/Effects/ColorSourceEffect.hpp @@ -14,7 +14,7 @@ namespace MDWMBlurGlassExt void SetColor(const D2D1_COLOR_F& color = { 0.f, 0.f, 0.f, 1.f }) { - float value[] = { color.r, color.g, color.b, color.a }; + float value[]{ color.r, color.g, color.b, color.a }; SetProperty(D2D1_FLOOD_PROP_COLOR, BoxValue(value)); } void SetColor(const winrt::Windows::UI::Color& color) diff --git a/DWMBlurGlassExt/Effects/CompositeEffect.hpp b/DWMBlurGlassExt/Effects/CompositeEffect.hpp index 639b061..d1daa91 100644 --- a/DWMBlurGlassExt/Effects/CompositeEffect.hpp +++ b/DWMBlurGlassExt/Effects/CompositeEffect.hpp @@ -31,21 +31,21 @@ namespace MDWMBlurGlassExt { SetProperty(D2D1_COMPOSITE_PROP_MODE, BoxValue(compositeMode)); } - void SetDestination(IGraphicsEffectSource* source) + void SetDestination(const winrt::Windows::Graphics::Effects::IGraphicsEffectSource& source) { SetInput(0, source); } - void SetDestination(const winrt::com_ptr& source) + void SetDestination(const winrt::Windows::UI::Composition::CompositionEffectSourceParameter& source) { - SetInput(0, source.get()); + SetInput(0, source); } - void SetSource(IGraphicsEffectSource* source) + void SetSource(const winrt::Windows::Graphics::Effects::IGraphicsEffectSource& source) { SetInput(1, source); } - void SetSource(const winrt::com_ptr& source) + void SetSource(const winrt::Windows::UI::Composition::CompositionEffectSourceParameter& source) { - SetInput(1, source.get()); + SetInput(1, source); } }; } \ No newline at end of file diff --git a/DWMBlurGlassExt/Effects/CrossFadeEffect.hpp b/DWMBlurGlassExt/Effects/CrossFadeEffect.hpp index cb99aff..fc3038b 100644 --- a/DWMBlurGlassExt/Effects/CrossFadeEffect.hpp +++ b/DWMBlurGlassExt/Effects/CrossFadeEffect.hpp @@ -21,31 +21,22 @@ namespace MDWMBlurGlassExt { SetProperty(D2D1_CROSSFADE_PROP_WEIGHT, BoxValue(weight)); } - void SetDestination(IGraphicsEffectSource* source) + void SetDestination(const winrt::Windows::Graphics::Effects::IGraphicsEffectSource& source) { SetInput(1, source); } - void SetSource(IGraphicsEffectSource* source) + void SetSource(const winrt::Windows::Graphics::Effects::IGraphicsEffectSource& source) { SetInput(0, source); } void SetDestination(const winrt::Windows::UI::Composition::CompositionEffectSourceParameter& source) { - SetInput(1, source.as().get()); + SetInput(1, source); } void SetSource(const winrt::Windows::UI::Composition::CompositionEffectSourceParameter& source) { - SetInput(0, source.as().get()); - } - - void SetDestination(const winrt::com_ptr source) - { - SetInput(1, source.get()); - } - void SetSource(const winrt::com_ptr source) - { - SetInput(0, source.get()); + SetInput(0, source); } }; } \ No newline at end of file diff --git a/DWMBlurGlassExt/Effects/ExposureEffect.hpp b/DWMBlurGlassExt/Effects/ExposureEffect.hpp index 8d4bd0c..afbed94 100644 --- a/DWMBlurGlassExt/Effects/ExposureEffect.hpp +++ b/DWMBlurGlassExt/Effects/ExposureEffect.hpp @@ -8,11 +8,11 @@ namespace MDWMBlurGlassExt public: ExposureEffect() : CanvasEffect{ CLSID_D2D1Exposure } { - SetExposure(); + SetExposureAmount(); } virtual ~ExposureEffect() = default; - void SetExposure(float exposure = 1.f) + void SetExposureAmount(float exposure = 1.f) { SetProperty(D2D1_EXPOSURE_PROP_EXPOSURE_VALUE, BoxValue(exposure)); } diff --git a/DWMBlurGlassExt/Effects/GaussianBlurEffect.hpp b/DWMBlurGlassExt/Effects/GaussianBlurEffect.hpp index 4d3ff50..5e7211b 100644 --- a/DWMBlurGlassExt/Effects/GaussianBlurEffect.hpp +++ b/DWMBlurGlassExt/Effects/GaussianBlurEffect.hpp @@ -22,7 +22,7 @@ namespace MDWMBlurGlassExt { SetProperty(D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION, BoxValue(optimizationMode)); } - void SetBorderMode(D2D1_BORDER_MODE borderMode = D2D1_BORDER_MODE_HARD) + void SetBorderMode(D2D1_BORDER_MODE borderMode = D2D1_BORDER_MODE_SOFT) { SetProperty(D2D1_GAUSSIANBLUR_PROP_BORDER_MODE, BoxValue(borderMode)); } diff --git a/DWMBlurGlassExt/Section/AccentBlurEffect.cpp b/DWMBlurGlassExt/Section/AccentBlurEffect.cpp index e8b038c..d45e553 100644 --- a/DWMBlurGlassExt/Section/AccentBlurEffect.cpp +++ b/DWMBlurGlassExt/Section/AccentBlurEffect.cpp @@ -415,7 +415,7 @@ namespace MDWMBlurGlassExt::AccentBlur (accentPolicy->nAccentState == ACCENT_DISABLED || accentPolicy->nAccentState == ACCENT_ENABLE_BLURBEHIND)) { auto collection = This->GetNCAreaVisualCollection(); - auto visual1 = This->GetNCAreaBackgroundVisual(); + auto visual1 = This->GetLegacyVisual(); auto visual2 = This->GetClientBlurVisual(); if (visual1 && visual2) diff --git a/DWMBlurGlassExt/Section/BackdropMaterials.cpp b/DWMBlurGlassExt/Section/BackdropMaterials.cpp index 72b6916..e97292f 100644 --- a/DWMBlurGlassExt/Section/BackdropMaterials.cpp +++ b/DWMBlurGlassExt/Section/BackdropMaterials.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2024 Maplespe、ALTaleX531 * - * This file is part of MToolBox and DWMBlurGlass and AcrylicEverywhere. + * This file is part of MToolBox and DWMBlurGlass and MDWMBlurGlassExt. * DWMBlurGlass is free software: you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation, either version 3 * of the License, or any later version. @@ -449,7 +449,7 @@ namespace MDWMBlurGlassExt float blurBalance ) { - // New Aero backdrop recipe by @ALTaleX531 (https://github.com/ALTaleX531/AcrylicEverywhere), @aubymori (normal layer fixes) + // New Aero backdrop recipe by @ALTaleX531 (https://github.com/ALTaleX531/MDWMBlurGlassExt), @aubymori (normal layer fixes) // @kfh83 for porting to DWMBlurGlass and minor modifications auto colorEffect{ winrt::make_self() }; diff --git a/DWMBlurGlassExt/Section/BackdropMaterials.h b/DWMBlurGlassExt/Section/BackdropMaterials.h index 00b48a3..4989c79 100644 --- a/DWMBlurGlassExt/Section/BackdropMaterials.h +++ b/DWMBlurGlassExt/Section/BackdropMaterials.h @@ -3,7 +3,7 @@ * * Copyright (C) 2024 Maplespe、ALTaleX531 * - * This file is part of MToolBox and DWMBlurGlass and AcrylicEverywhere. + * This file is part of MToolBox and DWMBlurGlass and MDWMBlurGlassExt. * DWMBlurGlass is free software: you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation, either version 3 * of the License, or any later version. @@ -144,6 +144,7 @@ namespace MDWMBlurGlassExt struct CGlassReflectionBackdrop : CBackdropEffect { static CGlassReflectionResources s_sharedResources; + static constexpr float parallaxIntensity{ 0.25 }; winrt::Windows::Foundation::Numerics::float2 relativeOffset{}; winrt::Windows::Foundation::Numerics::float2 fixedOffset{}; RECT currentWindowRect{}; diff --git a/DWMBlurGlassExt/Section/CompositedBackdrop.hpp b/DWMBlurGlassExt/Section/CompositedBackdrop.hpp new file mode 100644 index 0000000..f0b02f7 --- /dev/null +++ b/DWMBlurGlassExt/Section/CompositedBackdrop.hpp @@ -0,0 +1,1060 @@ +#pragma once +#include "DWMStruct.h" +#include "../Backdrops/uDwmBackdrop.hpp" +#include "../Backdrops/DCompBackdrop.hpp" +#include "../Backdrops/AcrylicBackdrop.hpp" +#include "../Backdrops/MicaBackdrop.hpp" +#include "../Backdrops/AeroBackdrop.hpp" +#include "../Backdrops/BlurBackdrop.hpp" +#include "../Backdrops/GlassReflectionBackdrop.hpp" +#include "VersionHelper.h" +#include "CommonDef.h" +#include + +namespace MDWMBlurGlassExt +{ + struct CNCVisualManager + { + DWM::CTopLevelWindow* window; + + CNCVisualManager(DWM::CTopLevelWindow* topLevelWindow = nullptr) : window{topLevelWindow} {} + void UpdateCloak(bool cloak) + { + if (!window) + { + return; + } + + DWM::CVisual* legacy{ nullptr }; + DWM::CVisual* accent{ nullptr }; + DWM::CVisual* clientBlur{ nullptr }; + DWM::CVisual* systemBackdrop{ nullptr }; + DWM::CVisual* accentColor{ nullptr }; + + if (cloak) + { + if ((legacy = window->GetLegacyVisual())) + { + legacy->Cloak(cloak); + } + if ((accent = window->GetAccent())) + { + accent->Cloak(cloak); + } + if ((clientBlur = window->GetClientBlurVisual())) + { + clientBlur->Cloak(cloak); + } + if ((systemBackdrop = window->GetSystemBackdropVisual())) + { + systemBackdrop->Cloak(cloak); + } + if ((accentColor = window->GetAccentColorVisual())) + { + accentColor->Cloak(cloak); + } + } + else + { + if ((legacy = window->GetLegacyVisual())) + { + legacy->Cloak(cloak); + } + if ((accent = window->GetAccent())) + { + accent->Cloak(cloak); + } + if ((clientBlur = window->GetClientBlurVisual())) + { + clientBlur->Cloak(cloak); + } + if ((systemBackdrop = window->GetSystemBackdropVisual())) + { + systemBackdrop->Cloak(cloak); + } + if ((accentColor = window->GetAccentColorVisual())) + { + accentColor->Cloak(cloak); + } + } + } + }; + + class CCompositedBackdrop : public winrt::implements + { + private: + struct WindowContext + { + bool useDarkMode{ false }; + bool windowActivated{ false }; + enum class WindowState : UCHAR + { + Normal, + Minimized, + Maximized + } windowState{ WindowState::Normal }; + bool updateNow{ true }; + } m_windowContext; + + MDWMBlurGlass::effectType m_type{ MDWMBlurGlass::effectType::None }; + bool m_enableGlassReflection{ false }; + bool m_enableBorders{ false }; + + winrt::Windows::Foundation::Numerics::float3 m_offset{ 0.f, 0.f, 1.f }; + winrt::Windows::Foundation::Numerics::float2 m_size{ 0.f, 0.f }; + wil::unique_hrgn m_clipRgn{ nullptr }; + wil::unique_hrgn m_borderRgn{ CreateRectRgn(0, 0, 0, 0) }; + + winrt::com_ptr m_interopDCompDevice{ nullptr }; + winrt::com_ptr m_borderVisual{ nullptr }; + winrt::com_ptr m_milBrush{ nullptr }; + DWM::CTopLevelWindow* m_window{ nullptr }; + DWM::CTopLevelWindow* m_sourceWindow{ nullptr }; + DWM::CWindowData* m_windowData{ nullptr }; + std::unique_ptr m_backdrop{ nullptr }; + std::unique_ptr m_glassReflection{ nullptr }; + CSharedVisual m_sharedVisual{}; + CNCVisualManager m_ncVisualManager{ nullptr }; + winrt::com_ptr m_sourceBackdropForAnimationUse{}; + + DWM::CTopLevelWindow* GetSourceWindow() const + { + return m_sourceWindow ? m_sourceWindow : m_window; + } + DWM::CTopLevelWindow* GetTargetWindow() const + { + return m_window; + } + void InitializeVisualConnection(bool disconnectPrevious) + { + THROW_IF_FAILED( + DWM::CCanvasVisual::Create( + m_borderVisual.put() + ) + ); + m_interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + if (disconnectPrevious && GetTargetWindow()) + { + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->Remove( + m_borderVisual.get() + ) + ); + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->Remove( + m_sharedVisual.udwmVisual.get() + ) + ); + } + + THROW_IF_FAILED(m_sharedVisual.InitializeDCompAnduDwmVisual(m_interopDCompDevice.get())); + if (GetTargetWindow()) + { + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->InsertRelative( + m_borderVisual.get(), + nullptr, + true, + true + ) + ); + m_borderVisual->AllowVisualTreeClone(false); + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->InsertRelative( + m_sharedVisual.udwmVisual.get(), + nullptr, + true, + true + ) + ); + } + m_sharedVisual.udwmVisual->AllowVisualTreeClone(false); + + if (disconnectPrevious) + { + m_backdrop.reset(); + m_glassReflection.reset(); + m_offset = { 0.f, 0.f, 1.f }; + m_size = { 0.f, 0.f }; + } + } + public: + const CSharedVisual& GetSharedVisual() const + { + return m_sharedVisual; + } + void Reset() + { + m_interopDCompDevice = nullptr; + } + CCompositedBackdrop(DWM::CTopLevelWindow* window) : + m_window{ window }, + m_windowData{ window->GetData() }, + m_sharedVisual{}, + m_ncVisualManager{ window } + { + m_ncVisualManager.UpdateCloak(true); + + InitializeVisualConnection(false); + } + CCompositedBackdrop( + const CCompositedBackdrop* backdrop, + DWM::CTopLevelWindow* dest + ) : + m_window{ dest }, + m_sourceWindow{ backdrop->m_window }, + m_windowData{ backdrop->m_windowData }, + m_sharedVisual{} + { + InitializeVisualConnection(false); + + bool allowNCBackgroundVisual{ backdrop->GetSourceWindow()->IsNCBackgroundVisualsCloneAllAllowed() }; + { + UpdateEffectType(allowNCBackgroundVisual ? backdrop->m_type : MDWMBlurGlass::effectType::None); + UpdateGlassReflectionState(backdrop->m_enableGlassReflection); + UpdateBordersState(allowNCBackgroundVisual ? backdrop->m_enableBorders : false); + THROW_IF_FAILED(UpdateClipRegion(allowNCBackgroundVisual ? backdrop->m_clipRgn.get() : nullptr)); + THROW_IF_FAILED( + UpdateRootAndChildren( + backdrop->m_offset, + backdrop->m_size, + backdrop->m_windowContext + ) + ); + THROW_IF_FAILED(UpdateBorderVisual()); + } + } + CCompositedBackdrop( + CCompositedBackdrop* backdrop + ) : CCompositedBackdrop{ backdrop, nullptr } + { + m_sourceBackdropForAnimationUse.copy_from(backdrop); + m_sourceBackdropForAnimationUse->m_sharedVisual.udwmVisual->ConnectToParent(false); + m_sourceBackdropForAnimationUse->m_sharedVisual.udwmVisual->Cloak(true); + } + ~CCompositedBackdrop() + { + if (GetTargetWindow()) + { + m_ncVisualManager.UpdateCloak(false); + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->Remove( + m_sharedVisual.udwmVisual.get() + ) + ); + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->Remove( + m_borderVisual.get() + ) + ); + } + if (m_sourceBackdropForAnimationUse) + { + m_sourceBackdropForAnimationUse->m_sharedVisual.udwmVisual->ConnectToParent(true); + m_sourceBackdropForAnimationUse->m_sharedVisual.udwmVisual->Cloak(false); + } + } + + CDCompBackdrop* GetMainBackdrop() const + { + return m_backdrop.get(); + } + + void UpdateEffectType(MDWMBlurGlass::effectType type) + { + if (m_type != type) + { + m_type = type; + if ( + m_sharedVisual.layerVisual && + m_backdrop && + m_backdrop->spriteVisual + ) + { + auto visualCollection{ m_sharedVisual.layerVisual.Children() }; + visualCollection.Remove(m_backdrop->spriteVisual); + m_backdrop.reset(); + } + } + } + void UpdateGlassReflectionState(bool enable) + { + if (m_enableGlassReflection != enable) + { + m_enableGlassReflection = enable; + if ( + m_sharedVisual.layerVisual && + m_glassReflection && + m_glassReflection->spriteVisual + ) + { + auto visualCollection{ m_sharedVisual.layerVisual.Children() }; + visualCollection.Remove(m_glassReflection->spriteVisual); + m_glassReflection.reset(); + } + } + } + void UpdateBordersState(bool enable) + { + if (m_enableBorders != enable) + { + m_enableBorders = enable; + + m_milBrush = nullptr; + THROW_IF_FAILED(m_borderVisual->ClearInstructions()); + } + } + + HRESULT UpdateClipRegion(HRGN hrgn) try + { + if (hrgn && !EqualRgn(hrgn, m_clipRgn.get())) + { + winrt::com_ptr geometry{nullptr}; + THROW_IF_FAILED( + DWM::ResourceHelper::CreateGeometryFromHRGN( + hrgn, + geometry.put() + ) + ); + m_sharedVisual.udwmVisual->GetVisualProxy()->SetClip(geometry.get()); + + m_clipRgn.reset(CreateRectRgn(0, 0, 0, 0)); + CopyRgn(m_clipRgn.get(), hrgn); + } + if (!hrgn && m_clipRgn) + { + m_sharedVisual.udwmVisual->GetVisualProxy()->SetClip(nullptr); + m_clipRgn.reset(); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT UpdateRootAndChildren( + const winrt::Windows::Foundation::Numerics::float3& offset, + const winrt::Windows::Foundation::Numerics::float2& size, + const WindowContext& context + ) try + { + auto is_visual_empty = [&] + { + return + ( + (size.x <= 0.f || size.y <= 0.f) || + ( + context.windowState == WindowContext::WindowState::Minimized && + m_windowContext.windowState == WindowContext::WindowState::Minimized + ) || + (m_clipRgn && EqualRgn(m_clipRgn.get(), wil::unique_hrgn{CreateRectRgn(0, 0, 0, 0)}.get())) + ); + }; + auto update_visual_info = [&] + { + if ( + m_offset != offset || + m_size != size || + memcmp(&context, &m_windowContext, sizeof(WindowContext)) != 0 + ) + { + m_offset = offset; + m_size = size; + m_windowContext = context; + + m_sharedVisual.layerVisual.Offset(m_offset); + m_sharedVisual.layerVisual.Size(m_size); + } + + THROW_IF_FAILED(UpdateBackdrop()); + THROW_IF_FAILED(UpdateGlassReflection()); + THROW_IF_FAILED(UpdateBorderVisual()); + m_ncVisualManager.UpdateCloak(true); + }; + + if (m_sharedVisual.layerVisual.IsVisible()) + { + if (is_visual_empty()) + { + m_sharedVisual.layerVisual.IsVisible(false); + } + update_visual_info(); + } + else if (!is_visual_empty()) + { + m_sharedVisual.layerVisual.IsVisible(true); + update_visual_info(); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT UpdateBackdrop() try + { + auto visualCollection{ m_sharedVisual.layerVisual.Children() }; + if (!m_backdrop && m_type != MDWMBlurGlass::effectType::None) + { + switch (m_type) + { + case MDWMBlurGlass::effectType::Acrylic: + { + m_backdrop.reset(new CAcrylicBackdrop); + THROW_IF_FAILED( + m_backdrop->Initialize( + visualCollection + ) + ); + break; + } + case MDWMBlurGlass::effectType::Mica: + { + m_backdrop.reset(new CMicaBackdrop); + THROW_IF_FAILED( + m_backdrop->Initialize( + visualCollection + ) + ); + break; + } + case MDWMBlurGlass::effectType::Aero: + { + m_backdrop.reset(new CAeroBackdrop); + THROW_IF_FAILED( + m_backdrop->Initialize( + visualCollection + ) + ); + break; + } + case MDWMBlurGlass::effectType::Blur: + { + m_backdrop.reset(new CBlurBackdrop); + THROW_IF_FAILED( + m_backdrop->Initialize( + visualCollection + ) + ); + break; + } + default: + break; + } + } + if (m_backdrop) + { + THROW_IF_FAILED( + m_backdrop->Update( + m_windowContext.useDarkMode, + m_windowContext.windowActivated + ) + ); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT UpdateGlassReflection() try + { + auto visualCollection{ m_sharedVisual.layerVisual.Children() }; + if (!m_glassReflection && m_enableGlassReflection) + { + m_glassReflection.reset(new CGlassReflectionBackdrop); + THROW_IF_FAILED( + m_glassReflection->Initialize(visualCollection) + ); + } + if (m_glassReflection) + { + THROW_IF_FAILED( + m_glassReflection->Update( + GetSourceWindow() + ) + ); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT UpdateBorderVisual() try + { + if (m_enableBorders) + { + RECT borderRect + { + static_cast(m_offset.x), + static_cast(m_offset.y), + static_cast(m_offset.x) + static_cast(m_size.x), + static_cast(m_offset.y) + static_cast(m_size.y) + }; + wil::unique_hrgn borderRgn{ CreateRectRgnIndirect(&borderRect) }; + { + borderRect.left += 1; + borderRect.top += 1; + borderRect.right -= 1; + borderRect.bottom -= 1; + } + wil::unique_hrgn innerRgn{ CreateRectRgnIndirect(&borderRect) }; + CombineRgn(borderRgn.get(), borderRgn.get(), innerRgn.get(), RGN_XOR); + + auto milBrushPtr{ GetSourceWindow()->GetBorderMilBrush() }; + if ( + ( + DWM::CDesktopManager::s_pDesktopManagerInstance->IsVanillaTheme() && + MDWMBlurGlass::os::buildNumber < 22000 + ) && + milBrushPtr && + ( + m_milBrush.get() != *milBrushPtr || + !EqualRgn(borderRgn.get(), m_borderRgn.get()) + ) && + m_windowContext.windowState != WindowContext::WindowState::Maximized + ) + { + THROW_IF_FAILED(m_borderVisual->ClearInstructions()); + m_milBrush.copy_from( + *GetSourceWindow()->GetBorderMilBrush() + ); + CopyRgn(m_borderRgn.get(), borderRgn.get()); + + winrt::com_ptr geometry{ nullptr }; + THROW_IF_FAILED( + DWM::ResourceHelper::CreateGeometryFromHRGN( + m_borderRgn.get(), + geometry.put() + ) + ); + if ( + m_milBrush && + geometry + ) + { + winrt::com_ptr instruction{ nullptr }; + THROW_IF_FAILED( + DWM::CDrawGeometryInstruction::Create( + m_milBrush.get(), + geometry.get(), + instruction.put() + ) + ); + THROW_IF_FAILED( + m_borderVisual->AddInstruction( + instruction.get() + ) + ); + } + } + else if (m_windowContext.windowState == WindowContext::WindowState::Maximized) + { + THROW_IF_FAILED(m_borderVisual->ClearInstructions()); + } + } + + return S_OK; + } + CATCH_RETURN() + + WindowContext GetCachedWindowContext() const + { + return m_windowContext; + } + WindowContext QueryCurrentWindowContext() + { + HWND hwnd{ m_windowData->GetHWND() }; + + WindowContext windowContext + { + m_windowData->IsUsingDarkMode(), + GetSourceWindow()->TreatAsActiveWindow(), + WindowContext::WindowState::Normal, + false + }; + if (IsMaximized(hwnd)) { windowContext.windowState = WindowContext::WindowState::Maximized; } + else if (IsMinimized(hwnd)) { windowContext.windowState = WindowContext::WindowState::Minimized; } + + return windowContext; + } + + HRESULT Update() try + { + auto is_device_valid = [&]() + { + if (!m_interopDCompDevice) return false; + + BOOL valid{ FALSE }; + THROW_IF_FAILED( + m_interopDCompDevice.as()->CheckDeviceState( + &valid + ) + ); + + return valid == TRUE; + }; + if (!is_device_valid()) + { + InitializeVisualConnection(true); + UpdateClipRegion(wil::unique_hrgn{ m_clipRgn.release() }.get()); + } + + HWND hwnd{ m_windowData->GetHWND() }; + const auto windowContext{ QueryCurrentWindowContext() }; + + RECT windowRect{}, borderRect{}; + THROW_HR_IF_NULL(E_INVALIDARG, GetSourceWindow()->GetActualWindowRect(&windowRect, false, true, true)); + THROW_HR_IF_NULL(E_INVALIDARG, GetSourceWindow()->GetActualWindowRect(&borderRect, false, true, false)); + MARGINS margins{}; + GetSourceWindow()->GetBorderMargins(&margins); + winrt::Windows::Foundation::Numerics::float3 offset + { + static_cast(!IsMaximized(hwnd) ? (windowRect.left - borderRect.left) : margins.cxLeftWidth), + static_cast(!IsMaximized(hwnd) ? (windowRect.top - borderRect.top) : margins.cyTopHeight), + 1.f + }; + winrt::Windows::Foundation::Numerics::float2 size + { + IsMinimized(hwnd) ? m_size.x : static_cast(wil::rect_width(windowRect)), + IsMinimized(hwnd) ? m_size.y : static_cast(wil::rect_height(windowRect)) + }; + + UpdateRootAndChildren( + offset, + size, + windowContext + ); + + return S_OK; + } + CATCH_RETURN() + }; + + class CCompositedAccentBackdrop : public winrt::implements + { + private: + struct WindowContext + { + enum class WindowState : UCHAR + { + Normal, + Minimized, + Maximized + } windowState{ WindowState::Normal }; + bool updateNow{ true }; + } m_windowContext; + + MDWMBlurGlass::effectType m_type{ MDWMBlurGlass::effectType::None }; + bool m_enableGlassReflection{ false }; + + winrt::Windows::Foundation::Numerics::float3 m_offset{ 0.f, 0.f, 1.f }; + winrt::Windows::Foundation::Numerics::float2 m_size{ 0.f, 0.f }; + RECT m_accentBlurRect{}; + DWM::ACCENT_POLICY m_accentPolicy{ DWM::ACCENT_INVALID_STATE }; + + winrt::com_ptr m_interopDCompDevice{ nullptr }; + DWM::CTopLevelWindow* m_window{ nullptr }; + DWM::CTopLevelWindow* m_sourceWindow{ nullptr }; + winrt::com_ptr m_clipRegion{ nullptr }; + + DWM::CWindowData* m_windowData{ nullptr }; + std::unique_ptr m_backdrop{ nullptr }; + std::unique_ptr m_glassReflection{ nullptr }; + CSharedVisual m_sharedVisual{}; + CNCVisualManager m_ncVisualManager{ nullptr }; + winrt::com_ptr m_sourceBackdropForAnimationUse{}; + + DWM::CTopLevelWindow* GetSourceWindow() const + { + return m_sourceWindow ? m_sourceWindow : m_window; + } + DWM::CTopLevelWindow* GetTargetWindow() const + { + return m_window; + } + void InitializeVisualConnection(bool disconnectPrevious) + { + m_interopDCompDevice.copy_from( + DWM::CDesktopManager::s_pDesktopManagerInstance->GetDCompositionInteropDevice() + ); + + if (disconnectPrevious && GetTargetWindow()) + { + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->Remove( + m_sharedVisual.udwmVisual.get() + ) + ); + } + THROW_IF_FAILED(m_sharedVisual.InitializeDCompAnduDwmVisual(m_interopDCompDevice.get())); + + auto compositor{ m_interopDCompDevice.as() }; + // TO-DO: Add accent dropshadow + // ... + + if (GetTargetWindow()) + { + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->InsertRelative( + m_sharedVisual.udwmVisual.get(), + nullptr, + true, + true + ) + ); + } + m_sharedVisual.udwmVisual->AllowVisualTreeClone(false); + if (disconnectPrevious) + { + m_backdrop.reset(); + m_glassReflection.reset(); + m_offset = { 0.f, 0.f, 1.f }; + m_size = { 0.f, 0.f }; + m_accentPolicy = { DWM::ACCENT_INVALID_STATE }; + } + } + bool IsContainShadow() + { + return + ( + (m_accentPolicy.nFlags & (1 << 5)) || + (m_accentPolicy.nFlags & (1 << 6)) || + (m_accentPolicy.nFlags & (1 << 7)) || + (m_accentPolicy.nFlags & (1 << 8)) + ); + } + public: + const CSharedVisual& GetSharedVisual() const + { + return m_sharedVisual; + } + void Reset() + { + m_interopDCompDevice = nullptr; + } + CCompositedAccentBackdrop(DWM::CTopLevelWindow* window) : + m_window{ window }, + m_windowData{ window->GetData() }, + m_sharedVisual{}, + m_ncVisualManager{ window } + { + m_ncVisualManager.UpdateCloak(true); + InitializeVisualConnection(false); + } + CCompositedAccentBackdrop(const CCompositedAccentBackdrop* backdrop, DWM::CTopLevelWindow* dest) : + m_window{ dest }, + m_sourceWindow{ backdrop->m_window }, + m_windowData{ backdrop->m_windowData }, + m_sharedVisual{} + { + InitializeVisualConnection(false); + + bool allowAccentVisual{ backdrop->GetSourceWindow()->GetAccent()->IsCloneAllowed() || backdrop->GetSourceWindow()->IsNCBackgroundVisualsCloneAllAllowed() }; + { + UpdateEffectType(allowAccentVisual ? backdrop->m_type : MDWMBlurGlass::effectType::None); + UpdateGlassReflectionState(backdrop->m_enableGlassReflection); + THROW_IF_FAILED(UpdateClipRegion()); + THROW_IF_FAILED( + UpdateRootAndChildren( + backdrop->m_offset, + backdrop->m_size, + backdrop->m_windowContext + ) + ); + } + } + CCompositedAccentBackdrop( + CCompositedAccentBackdrop* backdrop + ) : CCompositedAccentBackdrop{ backdrop, nullptr } + { + m_sourceBackdropForAnimationUse.copy_from(backdrop); + m_sourceBackdropForAnimationUse->m_sharedVisual.udwmVisual->ConnectToParent(false); + m_sourceBackdropForAnimationUse->m_sharedVisual.udwmVisual->Cloak(true); + } + ~CCompositedAccentBackdrop() + { + if (GetTargetWindow()) + { + m_ncVisualManager.UpdateCloak(false); + THROW_IF_FAILED( + GetTargetWindow()->GetVisual()->GetVisualCollection()->Remove( + m_sharedVisual.udwmVisual.get() + ) + ); + } + if (m_sourceBackdropForAnimationUse) + { + m_sourceBackdropForAnimationUse->m_sharedVisual.udwmVisual->ConnectToParent(true); + m_sourceBackdropForAnimationUse->m_sharedVisual.udwmVisual->Cloak(false); + } + } + + void UpdateEffectType(MDWMBlurGlass::effectType type) + { + if (m_type != type) + { + m_type = type; + if ( + m_sharedVisual.layerVisual && + m_backdrop && + m_backdrop->spriteVisual + ) + { + auto visualCollection{ m_sharedVisual.layerVisual.Children() }; + visualCollection.Remove(m_backdrop->spriteVisual); + m_backdrop.reset(); + } + } + } + void UpdateGlassReflectionState(bool enable) + { + if (m_enableGlassReflection != enable) + { + m_enableGlassReflection = enable; + if ( + m_sharedVisual.layerVisual && + m_glassReflection && + m_glassReflection->spriteVisual + ) + { + auto visualCollection{ m_sharedVisual.layerVisual.Children() }; + visualCollection.Remove(m_glassReflection->spriteVisual); + m_glassReflection.reset(); + } + } + } + + HRESULT UpdateClipRegion() + { + auto geometry{ GetSourceWindow()->GetAccent()->GetClipGeometry() }; + if (m_clipRegion.get() != geometry) + { + m_clipRegion.copy_from(geometry); + m_sharedVisual.udwmVisual->GetVisualProxy()->SetClip(geometry); + } + return S_OK; + } + + HRESULT UpdateRootAndChildren( + const winrt::Windows::Foundation::Numerics::float3& offset, + const winrt::Windows::Foundation::Numerics::float2& size, + const WindowContext& context + ) try + { + auto is_visual_empty = [&] + { + return + ( + (size.x <= 0.f || size.y <= 0.f) || + ( + context.windowState == WindowContext::WindowState::Minimized && + m_windowContext.windowState == WindowContext::WindowState::Minimized + ) + ); + }; + auto update_visual_info = [&] + { + if ( + m_offset != offset || + m_size != size || + memcmp(&context, &m_windowContext, sizeof(WindowContext)) != 0 + ) + { + m_offset = offset; + m_size = size; + m_windowContext = context; + + m_sharedVisual.layerVisual.Offset(m_offset); + m_sharedVisual.layerVisual.Size(m_size); + } + + THROW_IF_FAILED(UpdateGlassReflection()); + THROW_IF_FAILED(UpdateAccentPolicy()); + m_ncVisualManager.UpdateCloak(true); + }; + + if (m_sharedVisual.layerVisual.IsVisible()) + { + if (is_visual_empty()) + { + m_sharedVisual.layerVisual.IsVisible(false); + } + update_visual_info(); + } + else if (!is_visual_empty()) + { + m_sharedVisual.layerVisual.IsVisible(true); + update_visual_info(); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT UpdateBackdrop() try + { + auto visualCollection{ m_sharedVisual.layerVisual.Children() }; + if (!m_backdrop && m_type != MDWMBlurGlass::effectType::None) + { + switch (m_type) + { + case MDWMBlurGlass::effectType::Acrylic: + { + m_backdrop.reset(new CAccentAcrylicBackdrop); + THROW_IF_FAILED( + m_backdrop->Initialize( + visualCollection + ) + ); + break; + } + case MDWMBlurGlass::effectType::Mica: + { + m_backdrop.reset(new CAccentMicaBackdrop); + THROW_IF_FAILED( + m_backdrop->Initialize( + visualCollection + ) + ); + break; + } + case MDWMBlurGlass::effectType::Aero: + { + m_backdrop.reset(new CAccentAeroBackdrop); + THROW_IF_FAILED( + m_backdrop->Initialize( + visualCollection + ) + ); + break; + } + case MDWMBlurGlass::effectType::Blur: + { + m_backdrop.reset(new CAccentBlurBackdrop); + THROW_IF_FAILED( + m_backdrop->Initialize( + visualCollection + ) + ); + break; + } + default: + break; + } + } + if (m_backdrop) + { + THROW_IF_FAILED( + m_backdrop->Update( + m_accentPolicy + ) + ); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT UpdateGlassReflection() try + { + auto visualCollection{ m_sharedVisual.layerVisual.Children() }; + if (!m_glassReflection && m_enableGlassReflection) + { + m_glassReflection.reset(new CGlassReflectionBackdrop); + THROW_IF_FAILED( + m_glassReflection->Initialize(visualCollection) + ); + } + if (m_glassReflection) + { + THROW_IF_FAILED( + m_glassReflection->Update( + GetSourceWindow() + ) + ); + } + + return S_OK; + } + CATCH_RETURN() + + HRESULT UpdateAccentPolicy() + { + if (memcmp(&m_accentPolicy, m_windowData->GetAccentPolicy(), sizeof(DWM::ACCENT_POLICY)) != 0) + { + m_accentPolicy = *m_windowData->GetAccentPolicy(); + RETURN_IF_FAILED(UpdateBackdrop()); + } + return S_OK; + } + + WindowContext QueryCurrentWindowContext() + { + HWND hwnd{ m_windowData->GetHWND() }; + + WindowContext windowContext + { + WindowContext::WindowState::Normal, + false + }; + if (IsMaximized(hwnd)) { windowContext.windowState = WindowContext::WindowState::Maximized; } + else if (IsMinimized(hwnd)) { windowContext.windowState = WindowContext::WindowState::Minimized; } + + return windowContext; + } + + HRESULT Update() try + { + auto is_device_valid = [&]() + { + if (!m_interopDCompDevice) return false; + + BOOL valid{ FALSE }; + THROW_IF_FAILED( + m_interopDCompDevice.as()->CheckDeviceState( + &valid + ) + ); + + return valid == TRUE; + }; + if (!is_device_valid()) + { + InitializeVisualConnection(true); + THROW_IF_FAILED(UpdateClipRegion()); + } + + HWND hwnd{ m_windowData->GetHWND() }; + const auto windowContext{ QueryCurrentWindowContext() }; + + RECT windowRect{}, borderRect{}; + THROW_HR_IF_NULL(E_INVALIDARG, GetSourceWindow()->GetActualWindowRect(&windowRect, false, true, true)); + THROW_HR_IF_NULL(E_INVALIDARG, GetSourceWindow()->GetActualWindowRect(&borderRect, false, true, false)); + MARGINS margins{}; + GetSourceWindow()->GetBorderMargins(&margins); + winrt::Windows::Foundation::Numerics::float3 offset + { + static_cast(0.f), + static_cast(!IsMaximized(hwnd) ? 0.f : margins.cyTopHeight), + 1.f + }; + winrt::Windows::Foundation::Numerics::float2 size + { + IsMinimized(hwnd) ? m_size.x : static_cast(wil::rect_width(borderRect) + (IsMaximized(hwnd) ? margins.cxRightWidth + margins.cxLeftWidth : 0)), + IsMinimized(hwnd) ? m_size.y : static_cast(wil::rect_height(borderRect)) + }; + + THROW_IF_FAILED(UpdateClipRegion()); + THROW_IF_FAILED( + UpdateRootAndChildren( + offset, + size, + windowContext + ) + ); + + return S_OK; + } + CATCH_RETURN() + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/Section/CustomBackdropEffect.cpp b/DWMBlurGlassExt/Section/CustomBackdropEffect.cpp index c9edd8d..814bb5a 100644 --- a/DWMBlurGlassExt/Section/CustomBackdropEffect.cpp +++ b/DWMBlurGlassExt/Section/CustomBackdropEffect.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2024 Maplespe * - * This file is part of MToolBox and DWMBlurGlass and AcrylicEverywhere. + * This file is part of MToolBox and DWMBlurGlass and MDWMBlurGlassExt. * DWMBlurGlass is free software: you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation, either version 3 * of the License, or any later version. @@ -16,7 +16,7 @@ * If not, see . */ #include "CustomBackdropEffect.h" -#include "BackdropMaterials.h" +#include "VisualManager.hpp" #include "HookDef.h" #include "CommonDef.h" #include "wil.h" @@ -35,32 +35,45 @@ namespace MDWMBlurGlassExt::CustomBackdrop wil::unique_hrgn g_borderRgn = nullptr; CRgnGeometryProxy* const* g_titlebarGeometry = nullptr; wil::unique_hrgn g_titlebarRgn = nullptr; - CBackdropManager g_backdropManager{}; + CVisualManager g_visualManager{}; MinHook g_funCTopLevelWindow_InitializeVisualTreeClone { "CTopLevelWindow::InitializeVisualTreeClone", CTopLevelWindow_InitializeVisualTreeClone }; - MinHook g_funCTopLevelWindow_UpdateNCAreaBackground { "CTopLevelWindow::UpdateNCAreaBackground", CTopLevelWindow_UpdateNCAreaBackground }; - MinHook g_funCTopLevelWindow_Destructor { "CTopLevelWindow::~CTopLevelWindow", CTopLevelWindow_Destructor }; - MinHook g_funResourceHelper_CreateGeometryFromHRGN { "ResourceHelper::CreateGeometryFromHRGN", ResourceHelper_CreateGeometryFromHRGN }; + MinHook g_funCTopLevelWindow_OnClipUpdated + { + "CTopLevelWindow::OnClipUpdated", + CTopLevelWindow_OnClipUpdated + }; + MinHook g_funCTopLevelWindow_OnAccentPolicyUpdated + { + "CTopLevelWindow::OnAccentPolicyUpdated", + CTopLevelWindow_OnAccentPolicyUpdated + }; + MinHook g_funCWindowList_UpdateAccentBlurRect + { + "CWindowList::UpdateAccentBlurRect", + CWindowList_UpdateAccentBlurRect + }; + void Attach() { if (g_startup) return; @@ -72,6 +85,10 @@ namespace MDWMBlurGlassExt::CustomBackdrop g_funResourceHelper_CreateGeometryFromHRGN.Attach(); g_CTopLevelWindow_ValidateVisual_HookDispatcher.enable_hook_routine<2, true>(); + // accent overrider + g_funCTopLevelWindow_OnClipUpdated.Attach(); + g_funCTopLevelWindow_OnAccentPolicyUpdated.Attach(); + g_funCWindowList_UpdateAccentBlurRect.Attach(); } void Detach() @@ -84,7 +101,12 @@ namespace MDWMBlurGlassExt::CustomBackdrop g_funCTopLevelWindow_InitializeVisualTreeClone.Detach(); g_funCTopLevelWindow_Destructor.Detach(); - g_backdropManager.Shutdown(); + // accent overrider + g_funCTopLevelWindow_OnClipUpdated.Detach(); + g_funCTopLevelWindow_OnAccentPolicyUpdated.Detach(); + g_funCWindowList_UpdateAccentBlurRect.Detach(); + + g_visualManager.Shutdown(); g_startup = false; } @@ -92,7 +114,7 @@ namespace MDWMBlurGlassExt::CustomBackdrop void Refresh() { if (g_startup) - g_backdropManager.RefreshEffectConfig(); + g_visualManager.RefreshEffectConfig(); if (g_configData.blurmethod == blurMethod::CustomBlur && !g_startup) Attach(); else if (g_configData.blurmethod != blurMethod::CustomBlur && g_startup) @@ -102,29 +124,18 @@ namespace MDWMBlurGlassExt::CustomBackdrop HRESULT CTopLevelWindow_InitializeVisualTreeClone(CTopLevelWindow* This, CTopLevelWindow* topLevelWindow, UINT cloneOptions) { - bool cloneAllowed{ false }; - auto backdrop{ g_backdropManager.GetOrCreateBackdrop(This) }; - if (backdrop) - { - cloneAllowed = backdrop->GetVisual()->AllowVisualTreeClone(false); - } + HRESULT hr{ S_OK }; - HRESULT hr = g_funCTopLevelWindow_InitializeVisualTreeClone.call_org(This, topLevelWindow, cloneOptions); + hr = g_funCTopLevelWindow_InitializeVisualTreeClone.call_org(This, topLevelWindow, cloneOptions); - if (backdrop) + if (SUCCEEDED(hr)) { - backdrop->GetVisual()->AllowVisualTreeClone(cloneAllowed); - if (SUCCEEDED(hr)) - { - auto clonedBackdrop{ std::make_shared(g_configData.effectType, g_configData.reflection) }; - backdrop->InitializeVisualTreeClone(clonedBackdrop.get(), topLevelWindow); - g_backdropManager.CreateWithGivenBackdrop(topLevelWindow, clonedBackdrop); - } + g_visualManager.TryCloneBackdropForWindow(This, topLevelWindow); + g_visualManager.TryCloneAccentBackdropForWindow(This, topLevelWindow); } return hr; } - HRESULT CTopLevelWindow_UpdateNCAreaBackground(CTopLevelWindow* This) { g_windowOfInterest = This; @@ -137,20 +148,21 @@ namespace MDWMBlurGlassExt::CustomBackdrop g_borderGeometry = nullptr; g_titlebarGeometry = nullptr; - std::shared_ptr backdrop{ nullptr }; + winrt::com_ptr backdrop{ nullptr }; CWindowData* windowData{ This->GetData() }; - bool policyActive = false; - if (windowData) - { - if (auto policy = windowData->GetAccentPolicy(); policy->nAccentState == 5) - policyActive = false; - else - policyActive = CAccent::s_IsPolicyActive(policy); - } - if (windowData && !policyActive && AccentBlur::CheckWindowType(windowData->GetHWND()) - && This->HasNonClientBackground() && (backdrop = g_backdropManager.GetOrCreateBackdrop(This, true))) + if ( + windowData && + This->HasNonClientBackground() && + AccentBlur::CheckWindowType(windowData->GetHWND()) && + !windowData->GetAccentPolicy()->IsAccentBlurEnabled() && + (backdrop = g_visualManager.GetOrCreateBackdrop(This, true)) + ) { - if (g_borderRgn && g_titlebarRgn) + if ( + g_borderRgn && + g_titlebarRgn && + !This->IsSystemBackdropApplied() + ) { wil::unique_hrgn compositedRgn{ CreateRectRgn(0, 0, 0, 0) }; @@ -160,23 +172,17 @@ namespace MDWMBlurGlassExt::CustomBackdrop g_titlebarRgn.get(), RGN_OR ); - backdrop->Update( - This, - This->IsSystemBackdropApplied() ? nullptr : compositedRgn.get() - ); + backdrop->UpdateClipRegion(compositedRgn.get()); } else { - backdrop->Update( - This, - This->IsSystemBackdropApplied() ? nullptr : backdrop->GetClipRegion() - ); + backdrop->UpdateClipRegion(nullptr); } - This->ShowNCBackgroundVisualList(false); + backdrop->Update(); } - else if (g_backdropManager.GetOrCreateBackdrop(This)) + else if (g_visualManager.GetOrCreateBackdrop(This)) { - g_backdropManager.Remove(This); + g_visualManager.Remove(This); } g_borderRgn.reset(); @@ -184,36 +190,53 @@ namespace MDWMBlurGlassExt::CustomBackdrop return hr; } - HRESULT CTopLevelWindow_ValidateVisual(CTopLevelWindow* This) { - std::shared_ptr backdrop{ nullptr }; - CGlassReflectionBackdrop* glassReflection{ nullptr }; + winrt::com_ptr backdrop{ nullptr }; CWindowData* windowData{ This->GetData() }; - bool policyActive = false; if (windowData) { - g_window = windowData->GetHWND(); - if (auto policy = windowData->GetAccentPolicy(); policy->nAccentState == 5) - policyActive = false; - else - policyActive = CAccent::s_IsPolicyActive(policy); - } - if (windowData && AccentBlur::CheckWindowType(windowData->GetHWND()) && - !policyActive && (backdrop = g_backdropManager.GetOrCreateBackdrop(This)) - && (glassReflection = backdrop->GetGlassReflection())) - { - glassReflection->UpdateBackdrop(This); + { + winrt::com_ptr backdrop{ nullptr }; + if ( + This->HasNonClientBackground() && + AccentBlur::CheckWindowType(windowData->GetHWND()) && + (backdrop = g_visualManager.GetOrCreateBackdrop(This, true)) + ) + { + backdrop->UpdateGlassReflection(); + } + } + { + winrt::com_ptr backdrop{ nullptr }; + if ( + windowData->GetAccentPolicy()->IsAccentBlurEnabled() && + g_configData.overrideAccent && + (backdrop = g_visualManager.GetOrCreateAccentBackdrop(This, true)) + ) + { + backdrop->Update(); + } + else if ( + ( + !windowData->GetAccentPolicy()->IsAccentBlurEnabled() || + !g_configData.overrideAccent + ) && + g_visualManager.GetOrCreateAccentBackdrop(This) + ) + { + g_visualManager.RemoveAccent(This); + } + } } + return S_OK; } - void CTopLevelWindow_Destructor(CTopLevelWindow* This) { - g_backdropManager.Remove(This); + g_visualManager.Remove(This); g_funCTopLevelWindow_Destructor.call_org(This); } - HRESULT ResourceHelper_CreateGeometryFromHRGN(HRGN hrgn, CRgnGeometryProxy** geometry) { if (g_windowOfInterest) @@ -237,4 +260,99 @@ namespace MDWMBlurGlassExt::CustomBackdrop } return g_funResourceHelper_CreateGeometryFromHRGN.call_org(hrgn, geometry); } + + HRESULT STDMETHODCALLTYPE CTopLevelWindow_OnClipUpdated(DWM::CTopLevelWindow* This) + { + HRESULT hr{ S_OK }; + + hr = g_funCTopLevelWindow_OnClipUpdated.call_org(This); + + if (SUCCEEDED(hr)) + { + CWindowData* windowData{ This->GetData() }; + if (windowData) + { + winrt::com_ptr backdrop{ nullptr }; + if ( + windowData->GetAccentPolicy()->IsAccentBlurEnabled() && + g_configData.overrideAccent && + (backdrop = g_visualManager.GetOrCreateAccentBackdrop(This, true)) + ) + { + backdrop->UpdateClipRegion(); + } + else if ( + ( + !windowData->GetAccentPolicy()->IsAccentBlurEnabled() || + !g_configData.overrideAccent + ) && + g_visualManager.GetOrCreateAccentBackdrop(This) + ) + { + g_visualManager.RemoveAccent(This); + } + } + } + + return hr; + } + HRESULT STDMETHODCALLTYPE CTopLevelWindow_OnAccentPolicyUpdated(DWM::CTopLevelWindow* This) + { + HRESULT hr{ S_OK }; + + hr = g_funCTopLevelWindow_OnAccentPolicyUpdated.call_org(This); + + if (SUCCEEDED(hr)) + { + CWindowData* windowData{ This->GetData() }; + if (windowData) + { + winrt::com_ptr backdrop{ nullptr }; + if ( + windowData->GetAccentPolicy()->IsAccentBlurEnabled() && + g_configData.overrideAccent && + (backdrop = g_visualManager.GetOrCreateAccentBackdrop(This, true)) + ) + { + backdrop->UpdateAccentPolicy(); + } + else if ( + ( + !windowData->GetAccentPolicy()->IsAccentBlurEnabled() || + !g_configData.overrideAccent + ) && + g_visualManager.GetOrCreateAccentBackdrop(This) + ) + { + g_visualManager.RemoveAccent(This); + } + } + } + + return hr; + } + HRESULT STDMETHODCALLTYPE CWindowList_UpdateAccentBlurRect(DWM::CWindowList* This, const MILCMD_DWM_REDIRECTION_ACCENTBLURRECTUPDATE* milCmd) + { + HRESULT hr{ S_OK }; + + hr = g_funCWindowList_UpdateAccentBlurRect.call_org(This, milCmd); + + DWM::CWindowData* windowData{ nullptr }; + DWM::CTopLevelWindow* window{ nullptr }; + winrt::com_ptr backdrop{ nullptr }; + + if ( + SUCCEEDED(hr) && + SUCCEEDED(This->GetSyncedWindowDataByHwnd(milCmd->GetHwnd(), &windowData)) && + windowData && + (window = windowData->GetWindow()) && + window->GetAccent() && + (backdrop = g_visualManager.GetOrCreateAccentBackdrop(window)) + ) + { + backdrop->UpdateClipRegion(); + } + + return hr; + } } diff --git a/DWMBlurGlassExt/Section/CustomBackdropEffect.h b/DWMBlurGlassExt/Section/CustomBackdropEffect.h index 59439d4..fff5cd0 100644 --- a/DWMBlurGlassExt/Section/CustomBackdropEffect.h +++ b/DWMBlurGlassExt/Section/CustomBackdropEffect.h @@ -3,7 +3,7 @@ * * Copyright (C) 2024 Maplespe * - * This file is part of MToolBox and DWMBlurGlass and AcrylicEverywhere. + * This file is part of MToolBox and DWMBlurGlass and MDWMBlurGlassExt. * DWMBlurGlass is free software: you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation, either version 3 * of the License, or any later version. @@ -29,12 +29,24 @@ namespace MDWMBlurGlassExt::CustomBackdrop DWM::CTopLevelWindow* topLevelWindow, UINT cloneOptions ); - HRESULT WINAPI CTopLevelWindow_UpdateNCAreaBackground(DWM::CTopLevelWindow* This); - HRESULT WINAPI CTopLevelWindow_ValidateVisual(DWM::CTopLevelWindow* This); - void WINAPI CTopLevelWindow_Destructor(DWM::CTopLevelWindow* This); - HRESULT WINAPI ResourceHelper_CreateGeometryFromHRGN(HRGN hrgn, DWM::CRgnGeometryProxy** geometry); + + struct MILCMD + { + HWND GetHwnd() const + { + return *reinterpret_cast(reinterpret_cast(this) + 4); + } + LPCRECT GetRect() const + { + return reinterpret_cast(reinterpret_cast(this) + 12); + } + }; + struct MILCMD_DWM_REDIRECTION_ACCENTBLURRECTUPDATE : MILCMD {}; + HRESULT STDMETHODCALLTYPE CTopLevelWindow_OnClipUpdated(DWM::CTopLevelWindow* This); + HRESULT STDMETHODCALLTYPE CTopLevelWindow_OnAccentPolicyUpdated(DWM::CTopLevelWindow* This); + HRESULT STDMETHODCALLTYPE CWindowList_UpdateAccentBlurRect(DWM::CWindowList* This, const MILCMD_DWM_REDIRECTION_ACCENTBLURRECTUPDATE* milCmd); } \ No newline at end of file diff --git a/DWMBlurGlassExt/Section/VisualManager.hpp b/DWMBlurGlassExt/Section/VisualManager.hpp new file mode 100644 index 0000000..69d91f6 --- /dev/null +++ b/DWMBlurGlassExt/Section/VisualManager.hpp @@ -0,0 +1,211 @@ +#pragma once +#include "DWMStruct.h" +#include "CompositedBackdrop.hpp" +#include "CommonDef.h" +#include + +namespace MDWMBlurGlassExt +{ + class CVisualManager + { + public: + winrt::com_ptr GetOrCreateBackdrop(DWM::CTopLevelWindow* target, bool createIfNecessary = false) + { + auto it{ m_backdropMap.find(target) }; + + if (createIfNecessary) + { + if (it == m_backdropMap.end()) + { + auto result{ m_backdropMap.emplace(target, winrt::make_self(target)) }; + if (result.second == true) + { + it = result.first; + it->second->UpdateEffectType(CommonDef::g_configData.effectType); + it->second->UpdateGlassReflectionState(CommonDef::g_configData.reflection); + it->second->UpdateBordersState(!CommonDef::g_configData.extendBorder); + } + } + } + + return it == m_backdropMap.end() ? nullptr : it->second; + } + winrt::com_ptr GetOrCreateAccentBackdrop(DWM::CTopLevelWindow* target, bool createIfNecessary = false) + { + auto it{ m_accentBackdropMap.find(target) }; + + if (createIfNecessary) + { + if (it == m_accentBackdropMap.end()) + { + auto result{ m_accentBackdropMap.emplace(target, winrt::make_self(target)) }; + if (result.second == true) + { + it = result.first; + it->second->UpdateEffectType(CommonDef::g_configData.effectType); + it->second->UpdateGlassReflectionState(CommonDef::g_configData.reflection); + } + } + } + + return it == m_accentBackdropMap.end() ? nullptr : it->second; + } + winrt::com_ptr TryCloneBackdropForWindow(DWM::CTopLevelWindow* src, DWM::CTopLevelWindow* dest) + { + if (auto backdrop{ GetOrCreateBackdrop(src) }; backdrop) + { + auto it{ m_backdropMap.find(dest) }; + auto clonedBackdrop{ winrt::make_self(backdrop.get(), dest)}; + + if (it == m_backdropMap.end()) + { + auto result{ m_backdropMap.emplace(dest, clonedBackdrop) }; + if (result.second == true) { it = result.first; } + } + else + { + std::swap( + clonedBackdrop, + it->second + ); + } + + return it == m_backdropMap.end() ? nullptr : it->second; + } + + return nullptr; + } + winrt::com_ptr TryCloneAnimatedBackdropForWindow(DWM::CTopLevelWindow* src, DWM::CSecondaryWindowRepresentation* dest) + { + if (auto backdrop{ GetOrCreateBackdrop(src) }; backdrop) + { + auto it{ m_animatedBackdropMap.find(dest) }; + if (it != m_animatedBackdropMap.end()) + { + m_animatedBackdropMap.erase(it); + } + auto clonedBackdrop{ winrt::make_self(backdrop.get()) }; + auto result{ m_animatedBackdropMap.emplace(dest, clonedBackdrop) }; + if (result.second == true) { it = result.first; } + + return it == m_animatedBackdropMap.end() ? nullptr : it->second; + } + + return nullptr; + } + winrt::com_ptr TryCloneAnimatedAccentBackdropForWindow(DWM::CTopLevelWindow* src, DWM::CSecondaryWindowRepresentation* dest) + { + if (auto backdrop{ GetOrCreateAccentBackdrop(src) }; backdrop) + { + auto it{ m_animatedAccentBackdropMap.find(dest) }; + if (it != m_animatedAccentBackdropMap.end()) + { + m_animatedAccentBackdropMap.erase(it); + } + auto clonedBackdrop{ winrt::make_self(backdrop.get()) }; + auto result{ m_animatedAccentBackdropMap.emplace(dest, clonedBackdrop) }; + if (result.second == true) { it = result.first; } + + return it == m_animatedAccentBackdropMap.end() ? nullptr : it->second; + } + + return nullptr; + } + winrt::com_ptr TryCloneAccentBackdropForWindow(DWM::CTopLevelWindow* src, DWM::CTopLevelWindow* dest) + { + if (auto backdrop{ GetOrCreateAccentBackdrop(src) }; backdrop) + { + auto it{ m_accentBackdropMap.find(dest) }; + auto clonedBackdrop{ winrt::make_self(backdrop.get(), dest) }; + + if (it == m_accentBackdropMap.end()) + { + auto result{ m_accentBackdropMap.emplace(dest, clonedBackdrop) }; + if (result.second == true) { it = result.first; } + } + else + { + std::swap( + clonedBackdrop, + it->second + ); + } + + return it == m_accentBackdropMap.end() ? nullptr : it->second; + } + + return nullptr; + } + void Remove(DWM::CTopLevelWindow* target) + { + auto it{ m_backdropMap.find(target) }; + + if (it != m_backdropMap.end()) + { + m_backdropMap.erase(it); + } + } + void RemoveAnimatedBackdrop(DWM::CSecondaryWindowRepresentation* target) + { + auto it{ m_animatedBackdropMap.find(target) }; + + if (it != m_animatedBackdropMap.end()) + { + m_animatedBackdropMap.erase(it); + } + } + void RemoveAnimatedAccentBackdrop(DWM::CSecondaryWindowRepresentation* target) + { + auto it{ m_animatedAccentBackdropMap.find(target) }; + + if (it != m_animatedAccentBackdropMap.end()) + { + m_animatedAccentBackdropMap.erase(it); + } + } + void RemoveAccent(DWM::CTopLevelWindow* target) + { + auto it{ m_accentBackdropMap.find(target) }; + + if (it != m_accentBackdropMap.end()) + { + m_accentBackdropMap.erase(it); + } + } + void Shutdown() + { + m_backdropMap.clear(); + m_accentBackdropMap.clear(); + m_animatedBackdropMap.clear(); + m_animatedAccentBackdropMap.clear(); + } + void RefreshEffectConfig() + { + CAeroBackdrop::s_sharedResources.interopDCompDevice = nullptr; + CMicaBackdrop::s_sharedResources.interopDCompDevice = nullptr; + CAcrylicBackdrop::s_sharedResources.interopDCompDevice = nullptr; + CBlurBackdrop::s_sharedResources.interopDCompDevice = nullptr; + CGlassReflectionBackdrop::s_sharedResources.interopDCompDevice = nullptr; + + for (auto& effect : m_backdropMap | std::views::values) + { + effect->Reset(); + effect->UpdateEffectType(CommonDef::g_configData.effectType); + effect->UpdateGlassReflectionState(CommonDef::g_configData.reflection); + effect->UpdateBordersState(!CommonDef::g_configData.extendBorder); + } + + for (auto& effect : m_accentBackdropMap | std::views::values) + { + effect->Reset(); + effect->UpdateEffectType(CommonDef::g_configData.effectType); + effect->UpdateGlassReflectionState(CommonDef::g_configData.reflection); + } + } + private: + std::unordered_map> m_backdropMap{}; + std::unordered_map> m_accentBackdropMap{}; + std::unordered_map> m_animatedBackdropMap{}; + std::unordered_map> m_animatedAccentBackdropMap{}; + }; +} \ No newline at end of file diff --git a/DWMBlurGlassExt/minhook/MinHook.h b/DWMBlurGlassExt/minhook/MinHook.h index 15c0a87..5523c49 100644 --- a/DWMBlurGlassExt/minhook/MinHook.h +++ b/DWMBlurGlassExt/minhook/MinHook.h @@ -1,4 +1,4 @@ -/* +/* * MinHook - The Minimalistic API Hooking Library for x64/x86 * Copyright (C) 2009-2017 Tsuda Kageyu. * All rights reserved.