diff --git a/Common/config/rapidjsonhelper.hpp b/Common/config/rapidjsonhelper.hpp index f0fbd00f..7fb043d4 100644 --- a/Common/config/rapidjsonhelper.hpp +++ b/Common/config/rapidjsonhelper.hpp @@ -90,6 +90,13 @@ namespace rjh { writer.Bool(value); } + template T> + inline void Serialize(Writer& writer, T value, std::wstring_view key) + { + WriteKey(writer, key); + writer.Uint(value); + } + template inline void Serialize(Writer &writer, std::wstring_view value, std::wstring_view key) { @@ -135,6 +142,13 @@ namespace rjh { member = obj.GetBool(); } + inline void Deserialize(const value_t& obj, uint32_t& member, std::wstring_view key) + { + EnsureType(rj::Type::kNumberType, obj.GetType(), key); + + member = obj.GetUint(); + } + template requires std::is_enum_v inline void Deserialize(const value_t &obj, T &member, std::wstring_view key, const std::array &arr) diff --git a/Common/config/taskbarappearance.hpp b/Common/config/taskbarappearance.hpp index 1321d04d..f2c4f388 100644 --- a/Common/config/taskbarappearance.hpp +++ b/Common/config/taskbarappearance.hpp @@ -38,13 +38,8 @@ struct TaskbarAppearance { return false; } } - else - { - // always works in Windows 10, but broken in Windows 11 besides RTM with KB5006746. - // since we check IsExactBuild above, using an inverted IsAtLeastBuild here - // makes sure we return false for future versions of Windows 11 as well. - return !win32::IsAtLeastBuild(22000); - } + + return true; }(); return isBlurSupported; @@ -52,13 +47,15 @@ struct TaskbarAppearance { ACCENT_STATE Accent = ACCENT_NORMAL; Util::Color Color = { 0, 0, 0, 0 }; + uint32_t BlurRadius = 3; bool ShowPeek = true; bool ShowLine = true; constexpr TaskbarAppearance() noexcept = default; - constexpr TaskbarAppearance(ACCENT_STATE accent, Util::Color color, bool showPeek, bool showLine) noexcept : + constexpr TaskbarAppearance(ACCENT_STATE accent, Util::Color color, bool showPeek, bool showLine, uint32_t blurRadius = 3) noexcept : Accent(accent), Color(color), + BlurRadius(blurRadius), ShowPeek(showPeek), ShowLine(showLine) { } @@ -69,6 +66,7 @@ struct TaskbarAppearance { { rjh::Serialize(writer, Accent, ACCENT_KEY, ACCENT_MAP); rjh::Serialize(writer, Color.ToString(), COLOR_KEY); + rjh::Serialize(writer, BlurRadius, RADIUS_KEY); rjh::Serialize(writer, ShowPeek, SHOW_PEEK_KEY); rjh::Serialize(writer, ShowLine, SHOW_LINE_KEY); } @@ -114,6 +112,13 @@ struct TaskbarAppearance { }; } } + else if (key == RADIUS_KEY) + { + rjh::Deserialize(val, BlurRadius, key); + + if (BlurRadius > 250) + BlurRadius = 250; + } else if (key == SHOW_PEEK_KEY) { rjh::Deserialize(val, ShowPeek, key); @@ -139,6 +144,7 @@ struct TaskbarAppearance { static constexpr std::wstring_view ACCENT_KEY = L"accent"; static constexpr std::wstring_view COLOR_KEY = L"color"; + static constexpr std::wstring_view RADIUS_KEY = L"blur_radius"; static constexpr std::wstring_view SHOW_PEEK_KEY = L"show_peek"; static constexpr std::wstring_view SHOW_LINE_KEY = L"show_line"; #endif @@ -148,13 +154,14 @@ struct TaskbarAppearance { TaskbarAppearance(const txmp::TaskbarAppearance &winrtObj) noexcept : Accent(static_cast(winrtObj.Accent())), Color(winrtObj.Color()), + BlurRadius(winrtObj.BlurRadius()), ShowPeek(winrtObj.ShowPeek()), ShowLine(winrtObj.ShowLine()) { } operator txmp::TaskbarAppearance() const { - return { static_cast(Accent), Color, ShowPeek, ShowLine }; + return { static_cast(Accent), Color, ShowPeek, ShowLine, BlurRadius }; } #endif }; diff --git a/Common/winrt.hpp b/Common/winrt.hpp index 1c262a0e..a139144e 100644 --- a/Common/winrt.hpp +++ b/Common/winrt.hpp @@ -14,6 +14,7 @@ namespace winrt { namespace Controls {} namespace Hosting {} } + namespace UI::Composition {} } } @@ -27,3 +28,4 @@ namespace wfc = wf::Collections; namespace wux = winrt::Windows::UI::Xaml; namespace wuxc = wux::Controls; namespace wuxh = wux::Hosting; +namespace wuc = winrt::Windows::UI::Composition; diff --git a/ExplorerTAP/ExplorerTAP.vcxproj b/ExplorerTAP/ExplorerTAP.vcxproj index 02e9ce19..7fdead79 100644 --- a/ExplorerTAP/ExplorerTAP.vcxproj +++ b/ExplorerTAP/ExplorerTAP.vcxproj @@ -17,7 +17,7 @@ EXPLORERTAP_EXPORTS;WINRT_NO_MODULE_LOCK;RPCPROXY_ENABLE_CPP_NO_CINTERFACE;PROXY_CLSID_IS={ 0xe8721a60, 0x3798, 0x448f, { 0xa0, 0x1b, 0xdc, 0x4a, 0xf6, 0x5a, 0x78, 0xb } };ENTRY_PREFIX=PSFactory_;%(PreprocessorDefinitions) - Ole32.lib;OleAut32.lib;rpcrt4.lib;runtimeobject.lib;user32.lib + dxguid.lib;Ole32.lib;OleAut32.lib;rpcrt4.lib;runtimeobject.lib;user32.lib ExplorerTAP.def Windows @@ -46,6 +46,7 @@ + @@ -56,6 +57,7 @@ + @@ -64,6 +66,7 @@ + @@ -71,6 +74,7 @@ + diff --git a/ExplorerTAP/ExplorerTAP.vcxproj.filters b/ExplorerTAP/ExplorerTAP.vcxproj.filters index 6b4de7dc..8453fc48 100644 --- a/ExplorerTAP/ExplorerTAP.vcxproj.filters +++ b/ExplorerTAP/ExplorerTAP.vcxproj.filters @@ -54,6 +54,12 @@ Source Files + + Source Files + + + Source Files + @@ -80,6 +86,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/ExplorerTAP/GaussianBlurEffect.cpp b/ExplorerTAP/GaussianBlurEffect.cpp new file mode 100644 index 00000000..77d5f21d --- /dev/null +++ b/ExplorerTAP/GaussianBlurEffect.cpp @@ -0,0 +1,105 @@ +#pragma warning ( disable: 4100 26447 26490 26429 26818 ) +#include "GaussianBlurEffect.h" + +HRESULT __stdcall GaussianBlurEffect::GetEffectId(GUID* id) noexcept +{ + if (id == nullptr) + return E_INVALIDARG; + + *id = CLSID_D2D1GaussianBlur; + return S_OK; +} + +HRESULT __stdcall GaussianBlurEffect::GetNamedPropertyMapping(LPCWSTR name, UINT* index, awge::GRAPHICS_EFFECT_PROPERTY_MAPPING* mapping) noexcept +{ + if (index == nullptr || mapping == nullptr) + return E_INVALIDARG; + + if (_wcsicmp(name, L"BlurAmount") == 0) + { + *index = D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION; + *mapping = awge::GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT; + + return S_OK; + } + else if (_wcsicmp(name, L"Optimization") == 0) + { + *index = D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION; + *mapping = awge::GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT; + + return S_OK; + } + else if (_wcsicmp(name, L"BorderMode") == 0) + { + *index = D2D1_GAUSSIANBLUR_PROP_BORDER_MODE; + *mapping = awge::GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT; + + return S_OK; + } + + return E_INVALIDARG; +} + +HRESULT __stdcall GaussianBlurEffect::GetPropertyCount(UINT* count) noexcept +{ + if (count == nullptr) + return E_INVALIDARG; + + *count = 3; + return S_OK; +} + +HRESULT __stdcall GaussianBlurEffect::GetProperty(UINT index, ABI::Windows::Foundation::IPropertyValue** value) noexcept +{ + if (value == nullptr) + return E_INVALIDARG; + + switch (index) + { + case D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION: + { + reinterpret_cast(*value) = wf::PropertyValue::CreateSingle(BlurAmount).as(); + break; + } + case D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION: + { + reinterpret_cast(*value) = wf::PropertyValue::CreateUInt32((UINT32)Optimization).as(); + break; + } + case D2D1_GAUSSIANBLUR_PROP_BORDER_MODE: + { + reinterpret_cast(*value) = wf::PropertyValue::CreateUInt32((UINT32)BorderMode).as(); + break; + } + } + + return S_OK; +} + +HRESULT __stdcall GaussianBlurEffect::GetSource(UINT index, awge::IGraphicsEffectSource** source) noexcept +{ + if (source == nullptr) + return E_INVALIDARG; + + reinterpret_cast(*source) = Source; + return S_OK; +} + +HRESULT __stdcall GaussianBlurEffect::GetSourceCount(UINT* count) noexcept +{ + if (count == nullptr) + return E_INVALIDARG; + + *count = 1; + return S_OK; +} + +winrt::hstring GaussianBlurEffect::Name() +{ + return m_name; +} + +void GaussianBlurEffect::Name(winrt::hstring name) +{ + m_name = name; +} diff --git a/ExplorerTAP/GaussianBlurEffect.h b/ExplorerTAP/GaussianBlurEffect.h new file mode 100644 index 00000000..66ef7e3b --- /dev/null +++ b/ExplorerTAP/GaussianBlurEffect.h @@ -0,0 +1,33 @@ +#pragma once +#include "winrt.hpp" +#include "d2d1effects.h" +#include +#include +#include + +namespace wge = winrt::Windows::Graphics::Effects; +namespace awge = ABI::Windows::Graphics::Effects; + +struct GaussianBlurEffect : winrt::implements +{ +public: + // IGraphicsEffectD2D1Interop + HRESULT STDMETHODCALLTYPE GetEffectId(GUID* id) noexcept override; + HRESULT STDMETHODCALLTYPE GetNamedPropertyMapping(LPCWSTR name, UINT* index, awge::GRAPHICS_EFFECT_PROPERTY_MAPPING* mapping) noexcept override; + HRESULT STDMETHODCALLTYPE GetPropertyCount(UINT* count) noexcept override; + HRESULT STDMETHODCALLTYPE GetProperty(UINT index, ABI::Windows::Foundation::IPropertyValue** value) noexcept override; + HRESULT STDMETHODCALLTYPE GetSource(UINT index, awge::IGraphicsEffectSource** source) noexcept override; + HRESULT STDMETHODCALLTYPE GetSourceCount(UINT* count) noexcept override; + + // IGraphicsEffect + winrt::hstring Name(); + void Name(winrt::hstring name); + + wge::IGraphicsEffectSource Source; + + float BlurAmount = 3.0f; + D2D1_GAUSSIANBLUR_OPTIMIZATION Optimization = D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED; + D2D1_BORDER_MODE BorderMode = D2D1_BORDER_MODE_SOFT; +private: + winrt::hstring m_name = L"GaussianBlurEffect"; +}; diff --git a/ExplorerTAP/TaskbarBrush.idl b/ExplorerTAP/TaskbarBrush.idl index 17388ec0..262bd62d 100644 --- a/ExplorerTAP/TaskbarBrush.idl +++ b/ExplorerTAP/TaskbarBrush.idl @@ -1,5 +1,6 @@ enum TaskbarBrush { Acrylic, - SolidColor + SolidColor, + Blur }; diff --git a/ExplorerTAP/XamlCompositionBrush.cpp b/ExplorerTAP/XamlCompositionBrush.cpp new file mode 100644 index 00000000..a6007e9f --- /dev/null +++ b/ExplorerTAP/XamlCompositionBrush.cpp @@ -0,0 +1,34 @@ +#include "XamlCompositionBrush.h" + +std::atomic_int XamlCompositionBrush::m_connectionCounter = 0; + +XamlCompositionBrush::XamlCompositionBrush(wuc::CompositionBrush brush, bool disposeBrush) : m_brush(brush), m_disposeBrush(disposeBrush) { } + +void XamlCompositionBrush::OnConnected() +{ + CompositionBrush(m_brush); + + if (m_disposeBrush) + { + ++m_connectionCounter; + OnConnectionChanged(); + } +} + +void XamlCompositionBrush::OnDisconnected() +{ + if (m_disposeBrush) + { + --m_connectionCounter; + OnConnectionChanged(); + } +} + +void XamlCompositionBrush::OnConnectionChanged() +{ + if (!m_connectionCounter) + { + CompositionBrush(nullptr); + m_brush.Close(); + } +} diff --git a/ExplorerTAP/XamlCompositionBrush.h b/ExplorerTAP/XamlCompositionBrush.h new file mode 100644 index 00000000..823d16b1 --- /dev/null +++ b/ExplorerTAP/XamlCompositionBrush.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include "winrt.hpp" +#include "undefgetcurrenttime.h" +#include +#include +#include + +class XamlCompositionBrush : public wux::Media::XamlCompositionBrushBaseT +{ +public: + XamlCompositionBrush(wuc::CompositionBrush brush, bool disposeBrush = true); + + void OnConnected(); + void OnDisconnected(); +private: + wuc::CompositionBrush m_brush; + + bool m_disposeBrush; + static std::atomic_int m_connectionCounter; + + void OnConnectionChanged(); +}; diff --git a/ExplorerTAP/taskbarappearanceservice.cpp b/ExplorerTAP/taskbarappearanceservice.cpp index b0d10385..2c5f350f 100644 --- a/ExplorerTAP/taskbarappearanceservice.cpp +++ b/ExplorerTAP/taskbarappearanceservice.cpp @@ -6,6 +6,9 @@ #include "constants.hpp" #include "util/color.hpp" +#include "XamlCompositionBrush.h" +#include "GaussianBlurEffect.h" + extern "C" { _Check_return_ HRESULT STDAPICALLTYPE DLLGETCLASSOBJECT_ENTRY(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ void** ppv); @@ -62,8 +65,32 @@ HRESULT TaskbarAppearanceService::SetTaskbarAppearance(HWND taskbar, TaskbarBrus newBrush = std::move(solidBrush); } + else if (brush == Blur) + { + auto compositor = wuxh::ElementCompositionPreview::GetElementVisual(info.background.control).Compositor(); + auto backdropBrush = compositor.CreateBackdropBrush(); + auto blurEffect = winrt::make_self(); + blurEffect->Source = wuc::CompositionEffectSourceParameter(L"blurSource"); + blurEffect->BlurAmount = (float)color; + auto factory = compositor.CreateEffectFactory(blurEffect.as()); + auto blurBrush = factory.CreateBrush(); + blurBrush.SetSourceParameter(L"blurSource", backdropBrush); + + wux::Media::XamlCompositionBrushBase compBrush = winrt::make(blurBrush); + newBrush = std::move(compBrush); + } info.background.control.Fill(newBrush); + + // TODO: this is a hack, we need to find a better way to handle this + // As it's not a proper way to do it and doesn't work when the taskbar is recreated (e.g. in cases where the taskbar is automatically hidden) + // It probably doesn't work on multi-monitor scenarios as well + if (brush == Blur && !m_wallpaperRefreshed) + { + // Refresh the desktop wallpaper so that DWM invalidates the rect behind the taskbar otherwise we will have a black background behind the blur + SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE); + m_wallpaperRefreshed = true; + } } break; diff --git a/ExplorerTAP/taskbarappearanceservice.hpp b/ExplorerTAP/taskbarappearanceservice.hpp index 1c98a129..ddc9407b 100644 --- a/ExplorerTAP/taskbarappearanceservice.hpp +++ b/ExplorerTAP/taskbarappearanceservice.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "redefgetcurrenttime.h" #include @@ -70,5 +71,7 @@ class TaskbarAppearanceService : public winrt::implements m_WaitHandle; + bool m_wallpaperRefreshed; + static DWORD s_ProxyStubRegistrationCookie; }; diff --git a/TranslucentTB/taskbar/taskbarattributeworker.cpp b/TranslucentTB/taskbar/taskbarattributeworker.cpp index 1026a451..67626158 100644 --- a/TranslucentTB/taskbar/taskbarattributeworker.cpp +++ b/TranslucentTB/taskbar/taskbarattributeworker.cpp @@ -518,12 +518,22 @@ void TaskbarAttributeWorker::SetAttribute(taskbar_iterator taskbar, TaskbarAppea { brush = Acrylic; } + else if (config.Accent == ACCENT_ENABLE_BLURBEHIND) + { + brush = Blur; + } else if (config.Accent == ACCENT_ENABLE_GRADIENT) { color.A = 0xFF; } - HresultVerify(m_TaskbarService->SetTaskbarAppearance(taskbar->second.Taskbar.TaskbarWindow, brush, color.ToABGR()), spdlog::level::info, L"Failed to set taskbar brush"); + uint32_t colorValue; + if (config.Accent == ACCENT_ENABLE_BLURBEHIND) + colorValue = config.BlurRadius; + else + colorValue = color.ToABGR(); + + HresultVerify(m_TaskbarService->SetTaskbarAppearance(taskbar->second.Taskbar.TaskbarWindow, brush, colorValue), spdlog::level::info, L"Failed to set taskbar brush"); } } else diff --git a/Xaml/Models/Primitives/TaskbarAppearance.h b/Xaml/Models/Primitives/TaskbarAppearance.h index c685d39b..0584651f 100644 --- a/Xaml/Models/Primitives/TaskbarAppearance.h +++ b/Xaml/Models/Primitives/TaskbarAppearance.h @@ -9,21 +9,24 @@ namespace winrt::TranslucentTB::Xaml::Models::Primitives::implementation struct TaskbarAppearance : TaskbarAppearanceT { TaskbarAppearance() noexcept = default; - TaskbarAppearance(AccentState accent, Windows::UI::Color color, bool showPeek, bool showLine) noexcept : + TaskbarAppearance(AccentState accent, Windows::UI::Color color, bool showPeek, bool showLine, uint32_t blurRadius = 3) noexcept : m_Accent(accent), m_Color(color), + m_Radius(blurRadius), m_ShowPeek(showPeek), m_ShowLine(showLine) { } DECL_PROPERTY_FUNCS(AccentState, Accent, m_Accent); DECL_PROPERTY_FUNCS(Windows::UI::Color, Color, m_Color); + DECL_PROPERTY_FUNCS(uint32_t, BlurRadius, m_Radius); DECL_PROPERTY_FUNCS(bool, ShowPeek, m_ShowPeek); DECL_PROPERTY_FUNCS(bool, ShowLine, m_ShowLine); private: AccentState m_Accent = AccentState::Normal; Windows::UI::Color m_Color = { 0, 0, 0, 0 }; + uint32_t m_Radius = 3; bool m_ShowPeek = true; bool m_ShowLine = true; }; diff --git a/Xaml/Models/Primitives/TaskbarAppearance.idl b/Xaml/Models/Primitives/TaskbarAppearance.idl index dc100f90..eeefe8ca 100644 --- a/Xaml/Models/Primitives/TaskbarAppearance.idl +++ b/Xaml/Models/Primitives/TaskbarAppearance.idl @@ -5,7 +5,7 @@ namespace TranslucentTB.Xaml.Models.Primitives unsealed runtimeclass TaskbarAppearance { TaskbarAppearance(); - TaskbarAppearance(AccentState accent, Windows.UI.Color color, Boolean showPeek, Boolean showLine); + TaskbarAppearance(AccentState accent, Windows.UI.Color color, Boolean showPeek, Boolean showLine, UInt32 blurRadius); [noexcept] AccentState Accent; @@ -13,6 +13,9 @@ namespace TranslucentTB.Xaml.Models.Primitives [noexcept] Windows.UI.Color Color; + [noexcept] + UInt32 BlurRadius; + [noexcept] Boolean ShowPeek;