diff --git a/OpenGlass/BackdropManager.cpp b/OpenGlass/BackdropManager.cpp deleted file mode 100644 index 47eefae..0000000 --- a/OpenGlass/BackdropManager.cpp +++ /dev/null @@ -1,442 +0,0 @@ -#include "pch.h" -#include "GlassFramework.hpp" -#include "uDwmProjection.hpp" -#include "dcompProjection.hpp" -#include "BackdropManager.hpp" -#include "Utils.hpp" - -using namespace OpenGlass; -namespace OpenGlass::GlassFramework { extern BackdropManager::CompositedBackdropKind GetActualBackdropKind(uDwm::CTopLevelWindow* This); } -namespace OpenGlass::BackdropManager -{ - std::unordered_map> g_backdropMap{}; - void RedrawTopLevelWindow(uDwm::CTopLevelWindow* window) - { - __try - { - auto kind{ GlassFramework::GetActualBackdropKind(window) }; - // 0x10000 UpdateText - // 0x20000 UpdateIcon - // 0x100000 UpdateColorization - // ... - - if (os::buildNumber >= os::build_w11_22h2) - { - if (kind == CompositedBackdropKind::SystemBackdrop) - { - window->OnSystemBackdropUpdated(); - } - } - else - { - window->SetDirtyFlags(0x10000); - } - if (kind == CompositedBackdropKind::Accent) - { - window->OnAccentPolicyUpdated(); - } - if (os::buildNumber >= os::build_w10_1903) - { - window->OnClipUpdated(); - } - else - { - window->OnBlurBehindUpdated(); - } - } - __except (EXCEPTION_EXECUTE_HANDLER) {} - } - - class CCompositedBackdropVisual : public winrt::implements - { - bool m_backdropDataChanged{ false }; - bool m_activate{ false }; - bool m_visible{ true }; - DWORD m_state{}; - DWORD m_color{}; - DWORD m_accentFlags{}; - - CompositedBackdropKind m_kind{ CompositedBackdropKind::None }; - uDwm::CTopLevelWindow* m_window{ nullptr }; - uDwm::CWindowData* m_data{ nullptr }; - - wil::unique_hrgn m_gdiWindowRgn{ nullptr }; - wil::unique_hrgn m_clientBlurRgn{ nullptr }; - wil::unique_hrgn m_borderRgn{ nullptr }; - RECT m_captionRect{}; - RECT m_windowRect{}; - std::optional m_accentRect{ std::nullopt }; - wil::unique_hrgn m_compositedRgn{ nullptr }; - - void HandleChanges(); - void OnBackdropKindUpdated(CompositedBackdropKind kind); - void OnBackdropRegionChanged(wil::unique_hrgn& newBackdropRegion); - - POINT GetClientAreaOffset() const; - wil::unique_hrgn CompositeNewBackdropRegion() const - { - wil::unique_hrgn compositedRgn{ CreateRectRgn(0, 0, 0, 0) }; - wil::unique_hrgn nonClientRgn{ CreateRectRgn(0, 0, 0, 0) }; - wil::unique_hrgn realClientBlurRgn{ CreateRectRgn(0, 0, 0, 0) }; - wil::unique_hrgn captionRgn{ CreateRectRgnIndirect(&m_captionRect) }; - wil::unique_hrgn windowRgn{ CreateRectRgnIndirect(&m_windowRect) }; - - CombineRgn(nonClientRgn.get(), captionRgn.get(), m_borderRgn.get(), RGN_OR); - // DwmEnableBlurBehind - if (m_clientBlurRgn) - { - CopyRgn(realClientBlurRgn.get(), m_clientBlurRgn.get()); - auto clientOffset{ GetClientAreaOffset() }; - OffsetRgn(realClientBlurRgn.get(), clientOffset.x, clientOffset.y); - CombineRgn(compositedRgn.get(), compositedRgn.get(), realClientBlurRgn.get(), RGN_OR); - } - if (m_kind != CompositedBackdropKind::Accent) - { - CombineRgn(compositedRgn.get(), compositedRgn.get(), nonClientRgn.get(), RGN_OR); - if (m_kind == CompositedBackdropKind::SystemBackdrop) - { - CombineRgn(compositedRgn.get(), compositedRgn.get(), windowRgn.get(), RGN_OR); - } - } - else - { - CombineRgn(compositedRgn.get(), compositedRgn.get(), windowRgn.get(), RGN_OR); - if (m_accentRect) - { - wil::unique_hrgn accentRgn{ CreateRectRgnIndirect(&m_accentRect.value()) }; - CombineRgn(compositedRgn.get(), compositedRgn.get(), accentRgn.get(), RGN_AND); - } - - if ( - m_gdiWindowRgn && - m_data->GetAccentPolicy()->IsGdiRegionRespected() - ) - { - CombineRgn(compositedRgn.get(), compositedRgn.get(), m_gdiWindowRgn.get(), RGN_AND); - } - } - CombineRgn(compositedRgn.get(), compositedRgn.get(), windowRgn.get(), RGN_AND); - - return compositedRgn; - } - public: - CCompositedBackdropVisual(uDwm::CTopLevelWindow* window); - virtual ~CCompositedBackdropVisual(); - - void SetClientBlurRegion(HRGN region) override; - void SetCaptionRegion(HRGN region) override; - void SetBorderRegion(HRGN region) override; - void SetAccentRect(LPCRECT lprc) override; - void SetGdiWindowRegion(HRGN region) override; - void ValidateVisual() override; - void UpdateNCBackground() override; - - bool CanBeTrimmed() override - { - if (m_kind != CompositedBackdropKind::Accent && (!m_visible || m_window->IsTrullyMinimized())) - { - return true; - } - if (m_accentRect.has_value()) - { - return false; - } - if (m_gdiWindowRgn && m_data->GetAccentPolicy()->IsGdiRegionRespected()) - { - return false; - } - - return true; - } - }; -} - -POINT BackdropManager::CCompositedBackdropVisual::GetClientAreaOffset() const -{ - // GetClientBlurVisual() somtimes cannot work in ClonedVisual - // so here we use the original offset get from CTopLevelWindow::UpdateClientBlur - auto margins{ m_window->GetClientAreaContainerParentVisual()->GetMargins() }; - return { margins->cxLeftWidth, margins->cyTopHeight }; -} - -void BackdropManager::CCompositedBackdropVisual::OnBackdropRegionChanged(wil::unique_hrgn& newBackdropRegion) -{ - m_compositedRgn = std::move(newBackdropRegion); - - bool isVisible{}; - RECT regionBox{}; - auto regionType{ GetRgnBox(m_compositedRgn.get(), ®ionBox) }; - if ( - regionType == NULLREGION || - IsRectEmpty(®ionBox) - ) - { - isVisible = false; - } - else - { - isVisible = true; - } - - if (m_visible != isVisible) - { - m_visible = isVisible; - } - - if (!m_visible) - { - return; - } - - // ... -} - -void BackdropManager::CCompositedBackdropVisual::HandleChanges() try -{ - wil::unique_hrgn compositedRgn{ CompositeNewBackdropRegion() }; - if (!EqualRgn(m_compositedRgn.get(), compositedRgn.get())) - { - OnBackdropRegionChanged(compositedRgn); - } - m_backdropDataChanged = false; -} -CATCH_LOG_RETURN() - -BackdropManager::CCompositedBackdropVisual::CCompositedBackdropVisual(uDwm::CTopLevelWindow* window) : - m_window{ window }, - m_data{ window->GetData() } -{ - m_borderRgn.reset(CreateRectRgn(0, 0, 0, 0)); - m_compositedRgn.reset(CreateRectRgn(0, 0, 0, 0)); - - OnBackdropKindUpdated(GlassFramework::GetActualBackdropKind(window)); - if (m_kind == CompositedBackdropKind::Accent) - { - wil::unique_hrgn clipRgn{ CreateRectRgn(0, 0, 0, 0) }; - if (GetWindowRgn(m_data->GetHwnd(), clipRgn.get()) != ERROR) - { - SetGdiWindowRegion(clipRgn.get()); - } - else - { - SetGdiWindowRegion(nullptr); - } - } -} - -BackdropManager::CCompositedBackdropVisual::~CCompositedBackdropVisual() -{ -} - -void BackdropManager::CCompositedBackdropVisual::OnBackdropKindUpdated(CompositedBackdropKind kind) -{ - if (m_kind != kind) - { - m_kind = kind; - m_backdropDataChanged = true; - } -} -void BackdropManager::CCompositedBackdropVisual::SetClientBlurRegion(HRGN region) -{ - if (!m_clientBlurRgn) - { - m_clientBlurRgn.reset(CreateRectRgn(0, 0, 0, 0)); - } - CopyRgn(m_clientBlurRgn.get(), region); - m_backdropDataChanged = true; -} -void BackdropManager::CCompositedBackdropVisual::SetCaptionRegion(HRGN region) -{ - GetRgnBox(region, &m_captionRect); - m_backdropDataChanged = true; -} -void BackdropManager::CCompositedBackdropVisual::SetBorderRegion(HRGN region) -{ - CopyRgn(m_borderRgn.get(), region); - m_backdropDataChanged = true; -} -void BackdropManager::CCompositedBackdropVisual::SetAccentRect(LPCRECT lprc) -{ - if (lprc) - { - m_accentRect = *lprc; - m_gdiWindowRgn.reset(); - } - else if (m_accentRect.has_value()) - { - m_accentRect = std::nullopt; - if (m_kind == CompositedBackdropKind::Accent) - { - wil::unique_hrgn clipRgn{ CreateRectRgn(0, 0, 0, 0) }; - if (GetWindowRgn(m_data->GetHwnd(), clipRgn.get()) != ERROR) - { - m_gdiWindowRgn.reset(clipRgn.release()); - } - else - { - m_gdiWindowRgn.reset(); - } - } - } - m_backdropDataChanged = true; -} -void BackdropManager::CCompositedBackdropVisual::SetGdiWindowRegion(HRGN region) -{ - if (region) - { - if (!m_gdiWindowRgn) - { - m_gdiWindowRgn.reset(CreateRectRgn(0, 0, 0, 0)); - } - CopyRgn(m_gdiWindowRgn.get(), region); - m_accentRect = std::nullopt; - } - else if (m_gdiWindowRgn) - { - m_gdiWindowRgn.reset(); - m_accentRect = std::nullopt; - } - m_backdropDataChanged = true; -} - -void BackdropManager::CCompositedBackdropVisual::ValidateVisual() -{ - OnBackdropKindUpdated(GlassFramework::GetActualBackdropKind(m_window)); - if (m_backdropDataChanged) { HandleChanges(); } - if (m_visible) - { - - } -} -void BackdropManager::CCompositedBackdropVisual::UpdateNCBackground() -{ - RECT borderRect{}; - THROW_HR_IF_NULL(E_INVALIDARG, m_window->GetActualWindowRect(&borderRect, true, true, false)); - - if (!EqualRect(&m_windowRect, &borderRect)) - { - m_windowRect = borderRect; - m_backdropDataChanged = true; - } -} - - -size_t BackdropManager::GetCount() -{ - return g_backdropMap.size(); -} - -winrt::com_ptr BackdropManager::GetOrCreate(uDwm::CTopLevelWindow* window, bool createIfNecessary, bool silent) -{ - auto it{ g_backdropMap.find(window) }; - - if (createIfNecessary) - { - auto data{ window->GetData() }; - - if ( - data && - it == g_backdropMap.end() - ) - { - HWND targetWindow{ data->GetHwnd() }; - HWND shellWindow{ uDwm::GetShellWindowForCurrentDesktop() }; - - if (targetWindow != shellWindow) - { - auto result{ g_backdropMap.emplace(window, winrt::make(window)) }; - if (result.second == true) - { - it = result.first; - - if (!silent) - { - RedrawTopLevelWindow(window); - } - } - } - } - } - - return it == g_backdropMap.end() ? nullptr : it->second; -} - -winrt::com_ptr BackdropManager::GetOrCreateForAccentBlurRect(uDwm::CTopLevelWindow* window, LPCRECT accentBlurRect, bool createIfNecessary, bool silent) -{ - auto it{ g_backdropMap.find(window) }; - - auto result{ BackdropManager::GetOrCreate(window, createIfNecessary, true) }; - if (result && it == g_backdropMap.end()) - { - result->SetAccentRect(accentBlurRect); - if (!silent) - { - RedrawTopLevelWindow(window); - } - } - - return result; -} - -void BackdropManager::TryClone(uDwm::CTopLevelWindow* src, uDwm::CTopLevelWindow* dst, ICompositedBackdropVisual** visual) -{ - /*auto legacyVisual{ src->GetLegacyVisual() }; - if (auto backdrop{ GetOrCreate(src) }; backdrop && legacyVisual) - { - auto it{ g_backdropMap.find(dst) }; - if (it == g_backdropMap.end()) - { - winrt::com_ptr clonedBackdrop{ nullptr }; - - clonedBackdrop = legacyVisual->IsCloneAllowed() ? winrt::make(dst, reinterpret_cast(backdrop.get())) : winrt::make(src, dst); - - auto result{ g_backdropMap.emplace(dst, clonedBackdrop) }; - if (result.second == true) { it = result.first; } - } - - if (visual) - { - *visual = (it == g_backdropMap.end() ? nullptr : it->second.get()); - } - }*/ -} - -void BackdropManager::Remove(uDwm::CTopLevelWindow* window, bool silent) -{ - auto it{ g_backdropMap.find(window) }; - - if (it != g_backdropMap.end()) - { - g_backdropMap.erase(it); - - if (!silent) - { - RedrawTopLevelWindow(window); - } - } -} - -void BackdropManager::Trim(uDwm::CTopLevelWindow* window) -{ - auto it{ g_backdropMap.find(window) }; - - if (it != g_backdropMap.end() && it->second->CanBeTrimmed()) - { - g_backdropMap.erase(it); - } -} - -void BackdropManager::Shutdown() -{ - std::vector windowCollection{}; - for (const auto& [window, backdrop] : g_backdropMap) - { - windowCollection.push_back(window); - } - g_backdropMap.clear(); - - for (auto& window : windowCollection) - { - RedrawTopLevelWindow(window); - } -} \ No newline at end of file diff --git a/OpenGlass/BackdropManager.hpp b/OpenGlass/BackdropManager.hpp deleted file mode 100644 index 9757c36..0000000 --- a/OpenGlass/BackdropManager.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "framework.hpp" -#include "cpprt.hpp" -#include "winrt.hpp" -#include "uDwmProjection.hpp" -#include "ConfigurationFramework.hpp" - -namespace OpenGlass::BackdropManager -{ - enum class CompositedBackdropKind : CHAR - { - None = -1, - Legacy, - Accent, - SystemBackdrop - }; - enum class CompositedBackdropType : CHAR - { - None = -1, - Aero, - Acrylic, - Mica, - Blur - }; - - // [Guid("B1FDFCD4-F35C-44FD-8BF0-C2E7E6571461")] - DECLARE_INTERFACE_IID_(ICompositedBackdropVisual, IUnknown, "B1FDFCD4-F35C-44FD-8BF0-C2E7E6571461") - { - virtual void SetClientBlurRegion(HRGN region) = 0; - virtual void SetCaptionRegion(HRGN region) = 0; - virtual void SetBorderRegion(HRGN region) = 0; - virtual void SetAccentRect(LPCRECT lprc) = 0; - virtual void SetGdiWindowRegion(HRGN region) = 0; - - virtual void ValidateVisual() = 0; - virtual void UpdateNCBackground() = 0; - virtual bool CanBeTrimmed() = 0; - }; - - namespace Configuration - { - inline float g_roundRectRadius{ 0.f }; - - inline bool g_forceAccentColorization{ false }; - inline DWORD g_accentColor{ 0 }; - inline DWORD g_accentColorInactive{ 0 }; - } - - size_t GetCount(); - winrt::com_ptr GetOrCreate(uDwm::CTopLevelWindow* window, bool createIfNecessary = false, bool silent = false); - winrt::com_ptr GetOrCreateForAccentBlurRect(uDwm::CTopLevelWindow* window, LPCRECT accentBlurRect, bool createIfNecessary = false, bool silent = false); - void TryClone(uDwm::CTopLevelWindow* src, uDwm::CTopLevelWindow* dst, ICompositedBackdropVisual** visual = nullptr); - void Remove(uDwm::CTopLevelWindow* window, bool silent = false); - void Trim(uDwm::CTopLevelWindow* window); - void Shutdown(); -} \ No newline at end of file diff --git a/OpenGlass/CaptionTextHandler.cpp b/OpenGlass/CaptionTextHandler.cpp index 729e417..b06e2ae 100644 --- a/OpenGlass/CaptionTextHandler.cpp +++ b/OpenGlass/CaptionTextHandler.cpp @@ -299,9 +299,8 @@ HRESULT CaptionTextHandler::Startup() ); RETURN_LAST_ERROR_IF_NULL(g_IWICImagingFactory2_CreateBitmapFromHBITMAP_Org); - HMODULE udwmModule{ GetModuleHandleW(L"uDwm.dll") }; - g_DrawTextW_Org = reinterpret_cast(HookHelper::WriteIAT(udwmModule, "user32.dll", "DrawTextW", MyDrawTextW)); - g_CreateBitmap_Org = reinterpret_cast(HookHelper::WriteIAT(udwmModule, "gdi32.dll", "CreateBitmap", MyCreateBitmap)); + g_DrawTextW_Org = reinterpret_cast(HookHelper::WriteIAT(uDwm::g_moduleHandle, "user32.dll", "DrawTextW", MyDrawTextW)); + g_CreateBitmap_Org = reinterpret_cast(HookHelper::WriteIAT(uDwm::g_moduleHandle, "gdi32.dll", "CreateBitmap", MyCreateBitmap)); HookHelper::Detours::Write([]() { @@ -348,14 +347,13 @@ void CaptionTextHandler::Shutdown() g_IWICImagingFactory2_CreateBitmapFromHBITMAP_Org ); } - HMODULE udwmModule{ GetModuleHandleW(L"uDwm.dll") }; if (g_DrawTextW_Org) { - HookHelper::WriteIAT(udwmModule, "user32.dll", "DrawTextW", g_DrawTextW_Org); + HookHelper::WriteIAT(uDwm::g_moduleHandle, "user32.dll", "DrawTextW", g_DrawTextW_Org); } if (g_CreateBitmap_Org) { - HookHelper::WriteIAT(udwmModule, "gdi32.dll", "CreateBitmap", g_CreateBitmap_Org); + HookHelper::WriteIAT(uDwm::g_moduleHandle, "gdi32.dll", "CreateBitmap", g_CreateBitmap_Org); } g_textVisual = nullptr; diff --git a/OpenGlass/ConfigurationFramework.cpp b/OpenGlass/ConfigurationFramework.cpp index 6d73363..49bedca 100644 --- a/OpenGlass/ConfigurationFramework.cpp +++ b/OpenGlass/ConfigurationFramework.cpp @@ -1,8 +1,8 @@ #include "pch.h" #include "ConfigurationFramework.hpp" -#include "BackdropManager.hpp" #include "CaptionTextHandler.hpp" #include "GlassFramework.hpp" +#include "GlassRenderer.hpp" #include "CustomMsstyleLoader.hpp" #include "ServiceApi.hpp" @@ -16,6 +16,7 @@ namespace OpenGlass::ConfigurationFramework void ConfigurationFramework::Update(UpdateType type) { GlassFramework::UpdateConfiguration(type); + GlassRenderer::UpdateConfiguration(type); CaptionTextHandler::UpdateConfiguration(type); CustomMsstyleLoader::UpdateConfiguration(type); DwmFlush(); diff --git a/OpenGlass/ConfigurationFramework.hpp b/OpenGlass/ConfigurationFramework.hpp index 09c298d..186255a 100644 --- a/OpenGlass/ConfigurationFramework.hpp +++ b/OpenGlass/ConfigurationFramework.hpp @@ -1,7 +1,6 @@ #pragma once #include "framework.hpp" #include "cpprt.hpp" -#include "winrt.hpp" #include "uDwmProjection.hpp" namespace OpenGlass::ConfigurationFramework diff --git a/OpenGlass/CustomBlurEffect.cpp b/OpenGlass/CustomBlurEffect.cpp new file mode 100644 index 0000000..3a8a550 --- /dev/null +++ b/OpenGlass/CustomBlurEffect.cpp @@ -0,0 +1,364 @@ +#include "pch.h" +#include "CustomBlurEffect.hpp" + +using namespace OpenGlass; +const float CCustomBlurEffect::k_optimizations[16] +{ + 8.f, 6.f, 1.5f, 2.5f, static_cast(-42.28171817154095), 8.f, 6.f, 1.5f, + 2.5f, static_cast(-34.12687268616382), 12.f, 6.f, 2.f, 3.f, static_cast(-34.12687268616382), 0.f +}; + +CCustomBlurEffect::CCustomBlurEffect(ID2D1DeviceContext* deviceContext) +{ + winrt::copy_from_abi(m_deviceContext, deviceContext); +} + +// CropInput -> ScaleDown (optional) -> Border -> DirectionalBlurX -> DirectionalBlurY -> ScaleUp (optional) +HRESULT CCustomBlurEffect::Initialize() +{ + RETURN_IF_FAILED( + m_deviceContext->CreateEffect( + CLSID_D2D1Crop, + m_cropInputEffect.put() + ) + ); + RETURN_IF_FAILED( + m_deviceContext->CreateEffect( + CLSID_D2D1Scale, + m_scaleDownEffect.put() + ) + ); + RETURN_IF_FAILED( + m_deviceContext->CreateEffect( + CLSID_D2D1Border, + m_borderEffect.put() + ) + ); + RETURN_IF_FAILED( + m_deviceContext->CreateEffect( + CLSID_D2D1DirectionalBlurKernel, + m_directionalBlurXEffect.put() + ) + ); + RETURN_IF_FAILED( + m_deviceContext->CreateEffect( + CLSID_D2D1DirectionalBlurKernel, + m_directionalBlurYEffect.put() + ) + ); + RETURN_IF_FAILED( + m_deviceContext->CreateEffect( + CLSID_D2D1Scale, + m_scaleUpEffect.put() + ) + ); + + /* + RETURN_IF_FAILED( + m_cropInputEffect->SetValue(D2D1_PROPERTY_CACHED, TRUE) + );*/ + RETURN_IF_FAILED( + m_cropInputEffect->SetValue( + D2D1_CROP_PROP_BORDER_MODE, + D2D1_BORDER_MODE_SOFT + ) + ); + m_scaleDownEffect->SetInputEffect(0, m_cropInputEffect.get()); + RETURN_IF_FAILED(m_scaleDownEffect->SetValue(D2D1_SCALE_PROP_SHARPNESS, 1.f)); + RETURN_IF_FAILED( + m_scaleDownEffect->SetValue( + D2D1_SCALE_PROP_BORDER_MODE, + D2D1_BORDER_MODE_HARD + ) + ); + RETURN_IF_FAILED( + m_scaleDownEffect->SetValue( + D2D1_SCALE_PROP_INTERPOLATION_MODE, + D2D1_SCALE_INTERPOLATION_MODE_LINEAR + ) + ); + m_borderEffect->SetInputEffect(0, m_scaleDownEffect.get()); + RETURN_IF_FAILED( + m_borderEffect->SetValue( + D2D1_BORDER_PROP_EDGE_MODE_X, + D2D1_BORDER_EDGE_MODE_MIRROR + ) + ); + RETURN_IF_FAILED( + m_borderEffect->SetValue( + D2D1_BORDER_PROP_EDGE_MODE_Y, + D2D1_BORDER_EDGE_MODE_MIRROR + ) + ); + m_directionalBlurXEffect->SetInputEffect(0, m_borderEffect.get()); + RETURN_IF_FAILED( + m_directionalBlurXEffect->SetValue( + D2D1_DIRECTIONALBLURKERNEL_PROP_DIRECTION, + D2D1_DIRECTIONALBLURKERNEL_DIRECTION_X + ) + ); + m_directionalBlurYEffect->SetInputEffect(0, m_directionalBlurXEffect.get()); + RETURN_IF_FAILED( + m_directionalBlurYEffect->SetValue( + D2D1_DIRECTIONALBLURKERNEL_PROP_DIRECTION, + D2D1_DIRECTIONALBLURKERNEL_DIRECTION_Y + ) + ); + m_scaleUpEffect->SetInputEffect(0, m_directionalBlurYEffect.get()); + RETURN_IF_FAILED(m_scaleUpEffect->SetValue(D2D1_SCALE_PROP_SHARPNESS, 1.f)); + RETURN_IF_FAILED( + m_scaleUpEffect->SetValue( + D2D1_SCALE_PROP_BORDER_MODE, + D2D1_BORDER_MODE_HARD + ) + ); + RETURN_IF_FAILED( + m_scaleUpEffect->SetValue( + D2D1_SCALE_PROP_INTERPOLATION_MODE, + D2D1_SCALE_INTERPOLATION_MODE_LINEAR + ) + ); + m_initialized = true; + + return S_OK; +} + +float CCustomBlurEffect::DetermineOutputScale(float size, float blurAmount) +{ + float outputScale{ 1.f }; + if (size > 1.0) + { + float k{ blurAmount <= k_optimizations[2] ? 1.f : 0.5f }; + outputScale = k * fmaxf( + 0.1f, + fminf( + 1.f, + k_optimizations[0] / (blurAmount + k_optimizations[1]) + ) + ); + if (outputScale * size < 1.f) + { + return 1.f / size; + } + } + return outputScale; +} + +HRESULT STDMETHODCALLTYPE CCustomBlurEffect::Invalidate( + ID2D1Image* inputImage, + const D2D1_RECT_F& imageRectangle, + const D2D1_RECT_F& imageBounds, + bool transparentBlack, + float blurAmount +) +{ + if (!m_initialized) + { + RETURN_IF_FAILED(Initialize()); + } + if (transparentBlack || blurAmount == 0.f || (imageRectangle.right - imageRectangle.left <= 2.f || imageRectangle.bottom - imageRectangle.top <= 2.f)) + { + m_transparentBlack = true; + m_imageRectangle = imageRectangle; + winrt::copy_from_abi(m_effectOutput, inputImage); + return S_OK; + } + if (m_effectInput != inputImage) + { + m_effectInput = inputImage; + m_cropInputEffect->SetInput(0, inputImage); + } + + bool recalculateParams{ false }; + if (m_transparentBlack) + { + m_transparentBlack = false; + recalculateParams = true; + } + if (m_blurAmount != blurAmount) + { + m_blurAmount = blurAmount; + recalculateParams = true; + } + if (memcmp(&m_imageRectangle, &imageRectangle, sizeof(D2D1_RECT_F)) != 0) + { + m_imageRectangle = imageRectangle; + recalculateParams = true; + } + + if (!recalculateParams) + { + return S_OK; + } + + float extendAmount{ m_blurAmount * 3.f + 0.5f }; + D2D1_RECT_F actualImageRect + { + max(imageRectangle.left - extendAmount, imageBounds.left), + max(imageRectangle.top - extendAmount, imageBounds.top), + min(imageRectangle.right + extendAmount, imageBounds.right), + min(imageRectangle.bottom + extendAmount, imageBounds.bottom) + }; + RETURN_IF_FAILED( + m_cropInputEffect->SetValue( + D2D1_CROP_PROP_RECT, + actualImageRect + ) + ); + + D2D1_VECTOR_2F prescaleAmount + { + DetermineOutputScale(actualImageRect.right - actualImageRect.left, blurAmount), + DetermineOutputScale(actualImageRect.bottom - actualImageRect.top, blurAmount) + }; + D2D1_VECTOR_2F finalBlurAmount{ blurAmount, blurAmount }; + D2D1_VECTOR_2F outputOffset{ 0.f, 0.f }; + auto finalPrescaleAmount{ prescaleAmount }; + + if (prescaleAmount.x != 1.f && finalBlurAmount.x > k_optimizations[2]) + { + if (prescaleAmount.x <= 0.5f) + { + outputOffset.x = 0.25f; + finalPrescaleAmount.x *= 2.f; + } + } + if (prescaleAmount.y != 1.f && finalBlurAmount.y > k_optimizations[2]) + { + if (prescaleAmount.y <= 0.5f) + { + outputOffset.y = 0.25f; + finalPrescaleAmount.y *= 2.f; + } + } + + if (prescaleAmount.x == 1.f && prescaleAmount.y == 1.f) + { + m_directionalBlurYEffect->GetOutput(m_effectOutput.put()); + } + else + { + m_scaleUpEffect->GetOutput(m_effectOutput.put()); + RETURN_IF_FAILED( + m_scaleUpEffect->SetValue( + D2D1_SCALE_PROP_SCALE, + D2D1::Point2F( + 1.f / prescaleAmount.x, + 1.f / prescaleAmount.y + ) + ) + ); + } + + if (finalPrescaleAmount.x == 1.f && finalPrescaleAmount.y == 1.f) + { + m_borderEffect->SetInputEffect(0, m_cropInputEffect.get()); + } + else + { + m_scaleDownEffect->SetInputEffect(0, m_cropInputEffect.get()); + m_borderEffect->SetInputEffect(0, m_scaleDownEffect.get()); + RETURN_IF_FAILED( + m_scaleDownEffect->SetValue( + D2D1_SCALE_PROP_SCALE, + finalPrescaleAmount + ) + ); + + finalBlurAmount = D2D1::Vector2F( + finalBlurAmount.x * finalPrescaleAmount.x, + finalBlurAmount.y * finalPrescaleAmount.y + ); + } + + RETURN_IF_FAILED( + m_directionalBlurXEffect->SetValue( + D2D1_DIRECTIONALBLURKERNEL_PROP_STANDARD_DEVIATION, + finalBlurAmount.x + ) + ); + RETURN_IF_FAILED( + m_directionalBlurXEffect->SetValue( + D2D1_DIRECTIONALBLURKERNEL_PROP_KERNEL_RANGE_FACTOR, + k_optimizations[3] + ) + ); + RETURN_IF_FAILED( + m_directionalBlurXEffect->SetValue( + D2D1_DIRECTIONALBLURKERNEL_PROP_OPTIMIZATION_TRANSFORM, + (prescaleAmount.x != finalPrescaleAmount.x) ? D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_SCALE : D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_IDENDITY + ) + ); + RETURN_IF_FAILED( + m_directionalBlurYEffect->SetValue( + D2D1_DIRECTIONALBLURKERNEL_PROP_STANDARD_DEVIATION, + finalBlurAmount.y + ) + ); + RETURN_IF_FAILED( + m_directionalBlurYEffect->SetValue( + D2D1_DIRECTIONALBLURKERNEL_PROP_KERNEL_RANGE_FACTOR, + k_optimizations[3] + ) + ); + RETURN_IF_FAILED( + m_directionalBlurYEffect->SetValue( + D2D1_DIRECTIONALBLURKERNEL_PROP_OPTIMIZATION_TRANSFORM, + (prescaleAmount.y != finalPrescaleAmount.y) ? D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_SCALE : D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_IDENDITY + ) + ); +#ifdef _DEBUG + OutputDebugStringW( + std::format( + L"dblur_x: [deviation:{},direction:{},factor:{},transform:{}], dblur_y: [deviation:{},direction:{},factor:{},transform:{}], scale: [scale:[{},{}]]", + m_directionalBlurXEffect->GetValue(D2D1_DIRECTIONALBLURKERNEL_PROP_STANDARD_DEVIATION), + m_directionalBlurXEffect->GetValue(D2D1_DIRECTIONALBLURKERNEL_PROP_DIRECTION), + m_directionalBlurXEffect->GetValue(D2D1_DIRECTIONALBLURKERNEL_PROP_KERNEL_RANGE_FACTOR), + m_directionalBlurXEffect->GetValue(D2D1_DIRECTIONALBLURKERNEL_PROP_OPTIMIZATION_TRANSFORM), + m_directionalBlurYEffect->GetValue(D2D1_DIRECTIONALBLURKERNEL_PROP_STANDARD_DEVIATION), + m_directionalBlurYEffect->GetValue(D2D1_DIRECTIONALBLURKERNEL_PROP_DIRECTION), + m_directionalBlurYEffect->GetValue(D2D1_DIRECTIONALBLURKERNEL_PROP_KERNEL_RANGE_FACTOR), + m_directionalBlurYEffect->GetValue(D2D1_DIRECTIONALBLURKERNEL_PROP_OPTIMIZATION_TRANSFORM), + m_scaleDownEffect->GetValue(D2D1_SCALE_PROP_SCALE).x, + m_scaleDownEffect->GetValue(D2D1_SCALE_PROP_SCALE).y + ).c_str() + ); +#endif + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CCustomBlurEffect::Draw( + CONST D2D1_RECT_F& bounds, + D2D1_INTERPOLATION_MODE interpolationMode, + D2D1_COMPOSITE_MODE compositeMode +) +{ + m_deviceContext->DrawImage( + m_effectOutput.get(), + D2D1::Point2F( + bounds.left + m_imageRectangle.left, + bounds.top + m_imageRectangle.top + ), + D2D1::RectF( + m_imageRectangle.left, + m_imageRectangle.top, + min(bounds.left + m_imageRectangle.right, bounds.right), + min(bounds.top + m_imageRectangle.bottom, bounds.bottom) + ), + interpolationMode, + compositeMode + ); + /*{ + winrt::com_ptr brush{}; + m_deviceContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Red), brush.put()); + m_deviceContext->DrawRectangle(D2D1::RectF( + bounds.left + m_imageRectangle.left + 0.5f, + bounds.left + m_imageRectangle.top + 0.5f, + min(bounds.left + m_imageRectangle.right - 0.5f, bounds.right), + min(bounds.top + m_imageRectangle.bottom - 0.5f, bounds.bottom) + ), brush.get(), 1.f); + }*/ + + return S_OK; +} \ No newline at end of file diff --git a/OpenGlass/CustomBlurEffect.hpp b/OpenGlass/CustomBlurEffect.hpp new file mode 100644 index 0000000..2a05220 --- /dev/null +++ b/OpenGlass/CustomBlurEffect.hpp @@ -0,0 +1,81 @@ +#pragma once +#include "pch.h" +#include "framework.hpp" +#include "cpprt.hpp" + +namespace OpenGlass +{ + const GUID CLSID_D2D1DirectionalBlurKernel{ 0x58EB6E2A, 0x0D779, 0x4B7D, { 0x0AD, 0x39, 0x6F, 0x5A, 0x9F, 0x0C9, 0x0D2, 0x88} }; + enum D2D1_DIRECTIONALBLURKERNEL_PROP + { + D2D1_DIRECTIONALBLURKERNEL_PROP_STANDARD_DEVIATION, + D2D1_DIRECTIONALBLURKERNEL_PROP_DIRECTION, + D2D1_DIRECTIONALBLURKERNEL_PROP_KERNEL_RANGE_FACTOR, + D2D1_DIRECTIONALBLURKERNEL_PROP_OPTIMIZATION_TRANSFORM + }; + enum D2D1_DIRECTIONALBLURKERNEL_DIRECTION + { + D2D1_DIRECTIONALBLURKERNEL_DIRECTION_X, + D2D1_DIRECTIONALBLURKERNEL_DIRECTION_Y + }; + enum D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM + { + D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_IDENDITY, + D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_SCALE + }; + + // [Guid("01AA613C-2376-4B95-8A74-B94CA840D4D1")] + DECLARE_INTERFACE_IID_(ICustomBlurEffect, IUnknown, "01AA613C-2376-4B95-8A74-B94CA840D4D1") + { + virtual HRESULT STDMETHODCALLTYPE Invalidate( + ID2D1Image* inputImage, + const D2D1_RECT_F& imageRectangle, + const D2D1_RECT_F & imageBounds, + bool transparentBlack, + float blurAmount + ) = 0; + virtual HRESULT STDMETHODCALLTYPE Draw( + CONST D2D1_RECT_F & bounds, + D2D1_INTERPOLATION_MODE interpolationMode = D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, + D2D1_COMPOSITE_MODE compositeMode = D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY + ) = 0; + virtual float STDMETHODCALLTYPE GetBlurAmount() const = 0; + }; + + class CCustomBlurEffect : public winrt::implements + { + bool m_initialized{ false }; + bool m_transparentBlack{ false }; + float m_blurAmount{ 9.f }; + D2D1_RECT_F m_imageRectangle{}; + ID2D1Image* m_effectInput{ nullptr }; + winrt::com_ptr m_effectOutput{ nullptr }; + winrt::com_ptr m_deviceContext{ nullptr }; + winrt::com_ptr m_cropInputEffect{}; + winrt::com_ptr m_scaleDownEffect{}; + winrt::com_ptr m_borderEffect{}; + winrt::com_ptr m_directionalBlurXEffect{}; + winrt::com_ptr m_directionalBlurYEffect{}; + winrt::com_ptr m_scaleUpEffect{}; + + static const float k_optimizations[16]; + static float DetermineOutputScale(float size, float blurAmount); + HRESULT Initialize(); + public: + CCustomBlurEffect(ID2D1DeviceContext* deviceContext); + + HRESULT STDMETHODCALLTYPE Invalidate( + ID2D1Image* inputImage, + const D2D1_RECT_F& imageRectangle, + const D2D1_RECT_F& imageBounds, + bool transparentBlack, + float blurAmount + ) override; + HRESULT STDMETHODCALLTYPE Draw( + CONST D2D1_RECT_F& bounds, + D2D1_INTERPOLATION_MODE interpolationMode, + D2D1_COMPOSITE_MODE compositeMode + ) override; + float STDMETHODCALLTYPE GetBlurAmount() const override { return m_blurAmount; } + }; +} \ No newline at end of file diff --git a/OpenGlass/GlassEffectManager.cpp b/OpenGlass/GlassEffectManager.cpp new file mode 100644 index 0000000..8017b66 --- /dev/null +++ b/OpenGlass/GlassEffectManager.cpp @@ -0,0 +1,286 @@ +#include "pch.h" +#include "Utils.hpp" +#include "uDwmProjection.hpp" +#include "GlassFramework.hpp" +#include "GlassEffectManager.hpp" +#include "ReflectionRenderer.hpp" +#include "CustomBlurEffect.hpp" + +using namespace OpenGlass; +namespace OpenGlass::GlassEffectManager +{ + std::unordered_map> g_glassEffectMap{}; + + class CGlassEffect : public winrt::implements + { + bool m_recreateBlurBuffer{ true }; + D2D1_PIXEL_FORMAT m_backdropPixelFormat{}; + D2D1_SIZE_F m_desktopSize{}; + D2D1_RECT_F m_sourceRect{}; + D2D1_RECT_F m_sourceRectBackup{}; + D2D1_COLOR_F m_color{}; + float m_glassOpacity{}; + winrt::com_ptr m_deviceContext{ nullptr }; + winrt::com_ptr m_blurBuffer{ nullptr }; + winrt::com_ptr m_fallbackBlurBuffer{ nullptr }; + winrt::com_ptr m_colorEffect{ nullptr }; + winrt::com_ptr m_customBlurEffect{ nullptr }; + + static inline constexpr D2D1_PIXEL_FORMAT c_blurBufferPixelFormat{ DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE }; + public: + CGlassEffect(ID2D1DeviceContext* deviceContext) { winrt::copy_from_abi(m_deviceContext, deviceContext); } + HRESULT STDMETHODCALLTYPE SetSourceRect(const D2D1_RECT_F& rect) override; + HRESULT STDMETHODCALLTYPE Invalidate( + ID2D1Bitmap1* backdropBitmap, + const D2D1_RECT_F& rect, + const D2D1_COLOR_F& color, + float glassOpacity, + float blurAmount + ) override; + HRESULT STDMETHODCALLTYPE Render( + ID2D1Geometry* geometry + ) override; + }; +} + +HRESULT STDMETHODCALLTYPE GlassEffectManager::CGlassEffect::SetSourceRect(const D2D1_RECT_F& rect) +{ + if ( + (m_sourceRect.right - m_sourceRect.left) != (rect.right - rect.left) || + (m_sourceRect.bottom - m_sourceRect.top) != (rect.bottom - rect.top) + ) + { + m_recreateBlurBuffer = true; + } + m_sourceRect = rect; + + return S_OK; +} +HRESULT STDMETHODCALLTYPE GlassEffectManager::CGlassEffect::Invalidate( + ID2D1Bitmap1* backdropBitmap, + const D2D1_RECT_F& rect, + const D2D1_COLOR_F& color, + float glassOpacity, + float blurAmount +) +{ + m_backdropPixelFormat = backdropBitmap->GetPixelFormat(); + auto samePixelFormat{ m_backdropPixelFormat.format == c_blurBufferPixelFormat.format && m_backdropPixelFormat.alphaMode == c_blurBufferPixelFormat.alphaMode }; + m_recreateBlurBuffer = m_recreateBlurBuffer ? samePixelFormat : m_recreateBlurBuffer; + + if (!m_customBlurEffect) + { + m_customBlurEffect = winrt::make(m_deviceContext.get()); + } + if (!m_fallbackBlurBuffer) + { + RETURN_IF_FAILED( + m_deviceContext->CreateEffect( + CLSID_D2D1Flood, + m_fallbackBlurBuffer.put() + ) + ); + RETURN_IF_FAILED( + m_fallbackBlurBuffer->SetValue( + D2D1_FLOOD_PROP_COLOR, + D2D1::ColorF(0.f, 0.f, 0.f, 0.f) + ) + ); + } + if (!m_colorEffect) + { + RETURN_IF_FAILED( + m_deviceContext->CreateEffect( + CLSID_D2D1Flood, + m_colorEffect.put() + ) + ); + RETURN_IF_FAILED( + m_colorEffect->SetValue( + D2D1_FLOOD_PROP_COLOR, + D2D1::ColorF(0.f, 0.f, 0.f, 0.f) + ) + ); + } + if (m_recreateBlurBuffer) + { + m_recreateBlurBuffer = false; + + RETURN_IF_FAILED( + m_deviceContext->CreateBitmap( + D2D1::SizeU( + dwmcore::PixelAlign(m_sourceRect.right - m_sourceRect.left), + dwmcore::PixelAlign(m_sourceRect.bottom - m_sourceRect.top) + ), + nullptr, + 0, + D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_NONE, + c_blurBufferPixelFormat + ), + m_blurBuffer.put() + ) + ); + } + + m_color = color; + m_glassOpacity = glassOpacity; + RETURN_IF_FAILED( + m_colorEffect->SetValue( + D2D1_FLOOD_PROP_COLOR, + D2D1::Vector4F( + color.r * (color.a * glassOpacity), + color.g * (color.a * glassOpacity), + color.b * (color.a * glassOpacity), + color.a * glassOpacity + ) + ) + ); + if (samePixelFormat) + { + D2D1_POINT_2U dstPoint + { + dwmcore::PixelAlign(rect.left - m_sourceRect.left), + dwmcore::PixelAlign(rect.top - m_sourceRect.top) + }; + D2D1_RECT_U copyRect + { + dwmcore::PixelAlign(rect.left), + dwmcore::PixelAlign(rect.top), + dwmcore::PixelAlign(rect.right), + dwmcore::PixelAlign(rect.bottom) + }; + RETURN_IF_FAILED( + m_blurBuffer->CopyFromBitmap( + &dstPoint, + backdropBitmap, + ©Rect + ) + ); + m_sourceRectBackup = m_sourceRect; + m_desktopSize = backdropBitmap->GetSize(); + } + + D2D1_RECT_F invalidInputRect + { + rect.left - m_sourceRect.left, + rect.top - m_sourceRect.top, + rect.left - m_sourceRect.left + (rect.right - rect.left), + rect.top - m_sourceRect.top + (rect.bottom - rect.top) + }; + /*OutputDebugStringW( + std::format( + L"invalidInputRect:[{},{},{},{}]\n", + invalidInputRect.left, + invalidInputRect.top, + invalidInputRect.right, + invalidInputRect.bottom + ).c_str() + );*/ + auto backdropSize{ backdropBitmap->GetSize() }; + D2D1_SIZE_F imageSize{ m_sourceRect.right - m_sourceRect.left, m_sourceRect.bottom - m_sourceRect.top }; + auto truncatedWidth{ m_sourceRect.right - backdropSize.width }; + auto truncatedHeight{ m_sourceRect.bottom - backdropSize.height }; + D2D1_RECT_F imageBounds + { + max(0.f - m_sourceRect.left, 0.f), + max(0.f - m_sourceRect.top, 0.f), + truncatedWidth > 0.f ? max(imageSize.width - truncatedWidth, 0.f) : imageSize.width, + truncatedHeight > 0.f ? max(imageSize.height - truncatedHeight, 0.f) : imageSize.height + }; + + winrt::com_ptr inputImage{}; + if (!samePixelFormat) + { + m_fallbackBlurBuffer->GetOutput( + inputImage.put() + ); + } + else + { + winrt::copy_from_abi(inputImage, static_cast(m_blurBuffer.get())); + } + m_customBlurEffect->Invalidate( + inputImage.get(), + invalidInputRect, + imageBounds, + !samePixelFormat, + blurAmount + ); + + return S_OK; +} +HRESULT STDMETHODCALLTYPE GlassEffectManager::CGlassEffect::Render( + ID2D1Geometry* geometry +) +{ + D2D1_RECT_F bounds{}; + RETURN_IF_FAILED(geometry->GetBounds(nullptr, &bounds)); + + m_deviceContext->PushLayer( + D2D1::LayerParameters1( + bounds, + geometry, + D2D1_ANTIALIAS_MODE_ALIASED, + D2D1::IdentityMatrix(), + 1.f, + nullptr, + (m_backdropPixelFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE ? D2D1_LAYER_OPTIONS1_IGNORE_ALPHA : D2D1_LAYER_OPTIONS1_NONE) | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND + ), + nullptr + ); + m_customBlurEffect->Draw(bounds); + m_deviceContext->DrawImage( + m_colorEffect.get(), + D2D1::Point2F(bounds.left, bounds.top), + D2D1::RectF(0.f, 0.f, bounds.right - bounds.left, bounds.bottom - bounds.top), + D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR + ); + /*RETURN_IF_FAILED( + ReflectionRenderer::Draw( + m_deviceContext.get(), + D2D1::Point2F( + m_sourceRect.left, + m_sourceRect.top + ), + m_desktopSize, + bounds + ) + );*/ + m_deviceContext->PopLayer(); + m_sourceRect = m_sourceRectBackup; + + return S_OK; +} + +winrt::com_ptr GlassEffectManager::GetOrCreate(dwmcore::CGeometry* geometry, ID2D1DeviceContext* deviceContext, bool createIfNecessary) +{ + auto it{ g_glassEffectMap.find(geometry) }; + + if (createIfNecessary) + { + if (it == g_glassEffectMap.end()) + { + auto result{ g_glassEffectMap.emplace(geometry, winrt::make(deviceContext)) }; + if (result.second == true) + { + it = result.first; + } + } + } + + return it == g_glassEffectMap.end() ? nullptr : it->second; +} +void GlassEffectManager::Remove(dwmcore::CGeometry* geometry) +{ + auto it{ g_glassEffectMap.find(geometry) }; + + if (it != g_glassEffectMap.end()) + { + g_glassEffectMap.erase(it); + } +} +void GlassEffectManager::Shutdown() +{ + g_glassEffectMap.clear(); +} \ No newline at end of file diff --git a/OpenGlass/GlassEffectManager.hpp b/OpenGlass/GlassEffectManager.hpp new file mode 100644 index 0000000..f5dc6ba --- /dev/null +++ b/OpenGlass/GlassEffectManager.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "framework.hpp" +#include "cpprt.hpp" +#include "uDwmProjection.hpp" + +namespace OpenGlass::GlassEffectManager +{ + // [Guid("01AA613C-2376-4B95-8A74-B94CA840D4D1")] + DECLARE_INTERFACE_IID_(IGlassEffect, IUnknown, "01AA613C-2376-4B95-8A74-B94CA840D4D1") + { + virtual HRESULT STDMETHODCALLTYPE SetSourceRect(const D2D1_RECT_F& rect) = 0; + virtual HRESULT STDMETHODCALLTYPE Invalidate( + ID2D1Bitmap1* backdropBitmap, + const D2D1_RECT_F& rect, + const D2D1_COLOR_F& color, + float glassOpacity, + float blurAmount + ) = 0; + virtual HRESULT STDMETHODCALLTYPE Render( + ID2D1Geometry* geometry + ) = 0; + }; + + winrt::com_ptr GetOrCreate( + dwmcore::CGeometry* geometry, + ID2D1DeviceContext* deviceContext = nullptr, + bool createIfNecessary = false + ); + void Remove(dwmcore::CGeometry* geometry); + void Shutdown(); +} \ No newline at end of file diff --git a/OpenGlass/GlassFramework.cpp b/OpenGlass/GlassFramework.cpp index 97ac9de..8593cf7 100644 --- a/OpenGlass/GlassFramework.cpp +++ b/OpenGlass/GlassFramework.cpp @@ -1,158 +1,96 @@ #include "pch.h" #include "GlassFramework.hpp" #include "uDwmProjection.hpp" -#include "GeometryRecorder.hpp" -#include "BackdropManager.hpp" #include "dwmcoreProjection.hpp" +#include "GeometryRecorder.hpp" +#include "VisualManager.hpp" +#include "GlassSharedData.hpp" using namespace OpenGlass; namespace OpenGlass::GlassFramework { - BackdropManager::CompositedBackdropKind GetActualBackdropKind(uDwm::CTopLevelWindow* This); - + HRGN WINAPI MyCreateRoundRectRgn(int x1, int y1, int x2, int y2, int w, int h); HRESULT STDMETHODCALLTYPE MyCDrawGeometryInstruction_Create(uDwm::CBaseLegacyMilBrushProxy* brush, uDwm::CBaseGeometryProxy* geometry, uDwm::CDrawGeometryInstruction** instruction); HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_UpdateNCAreaBackground(uDwm::CTopLevelWindow* This); HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_UpdateClientBlur(uDwm::CTopLevelWindow* This); - HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_ValidateVisual(uDwm::CTopLevelWindow* This); - HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_UpdateAccent(uDwm::CTopLevelWindow* This, bool visibleAndUncloaked); + HRESULT STDMETHODCALLTYPE MyCAccent_UpdateAccentPolicy(uDwm::CAccent* This, LPCRECT lprc, uDwm::ACCENT_POLICY* policy, uDwm::CBaseGeometryProxy* geometry); + HRESULT STDMETHODCALLTYPE MyCAccent__UpdateSolidFill(uDwm::CAccent* This, uDwm::CRenderDataVisual* visual, DWORD color, const D2D1_RECT_F* lprc, float opacity); + HRESULT STDMETHODCALLTYPE MyCRenderDataVisual_AddInstruction(uDwm::CRenderDataVisual* This, uDwm::CRenderDataInstruction* instruction); DWORD STDMETHODCALLTYPE MyCTopLevelWindow_CalculateBackgroundType(uDwm::CTopLevelWindow* This); HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_UpdateSystemBackdropVisual(uDwm::CTopLevelWindow* This); void STDMETHODCALLTYPE MyCTopLevelWindow_Destructor(uDwm::CTopLevelWindow* This); - HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_InitializeVisualTreeClone(uDwm::CTopLevelWindow* This, uDwm::CTopLevelWindow* window, UINT cloneOptions); - HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_CloneVisualTree(uDwm::CTopLevelWindow* This, uDwm::CTopLevelWindow** window, bool unknown); - HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_CloneVisualTree_Pre1903(uDwm::CTopLevelWindow* This, uDwm::CTopLevelWindow** window, bool unknown1, bool unknown2, bool unknown3); - HRESULT STDMETHODCALLTYPE MyCTopLevelWindow_OnClipUpdated(uDwm::CTopLevelWindow* This); - struct MILCMD_DWM_REDIRECTION_ACCENTBLURRECTUPDATE - { - HWND GetHwnd() const - { - return *reinterpret_cast(reinterpret_cast(this) + 4); - } - LPCRECT GetRect() const - { - return reinterpret_cast(reinterpret_cast(this) + 12); - } - }; - HRESULT STDMETHODCALLTYPE MyCWindowList_UpdateAccentBlurRect(uDwm::CWindowList* This, const MILCMD_DWM_REDIRECTION_ACCENTBLURRECTUPDATE* milCmd); + decltype(&MyCreateRoundRectRgn) g_CreateRoundRectRgn_Org{ nullptr }; decltype(&MyCDrawGeometryInstruction_Create) g_CDrawGeometryInstruction_Create_Org{ nullptr }; decltype(&MyCTopLevelWindow_UpdateNCAreaBackground) g_CTopLevelWindow_UpdateNCAreaBackground_Org{ nullptr }; decltype(&MyCTopLevelWindow_UpdateClientBlur) g_CTopLevelWindow_UpdateClientBlur_Org{ nullptr }; - decltype(&MyCTopLevelWindow_ValidateVisual) g_CTopLevelWindow_ValidateVisual_Org{ nullptr }; - decltype(&MyCTopLevelWindow_UpdateAccent) g_CTopLevelWindow_UpdateAccent_Org{ nullptr }; + decltype(&MyCAccent_UpdateAccentPolicy) g_CAccent_UpdateAccentPolicy_Org{ nullptr }; + decltype(&MyCAccent__UpdateSolidFill) g_CAccent__UpdateSolidFill_Org{ nullptr }; + decltype(&MyCRenderDataVisual_AddInstruction) g_CRenderDataVisual_AddInstruction_Org{ nullptr }; decltype(&MyCTopLevelWindow_CalculateBackgroundType) g_CTopLevelWindow_CalculateBackgroundType_Org{ nullptr }; decltype(&MyCTopLevelWindow_UpdateSystemBackdropVisual) g_CTopLevelWindow_UpdateSystemBackdropVisual_Org{ nullptr }; decltype(&MyCTopLevelWindow_Destructor) g_CTopLevelWindow_Destructor_Org{ nullptr }; - decltype(&MyCTopLevelWindow_InitializeVisualTreeClone) g_CTopLevelWindow_InitializeVisualTreeClone_Org{ nullptr }; - decltype(&MyCTopLevelWindow_CloneVisualTree) g_CTopLevelWindow_CloneVisualTree_Org{ nullptr }; - decltype(&MyCTopLevelWindow_CloneVisualTree_Pre1903) g_CTopLevelWindow_CloneVisualTree_Pre1903_Org{ nullptr }; - decltype(&MyCTopLevelWindow_OnClipUpdated) g_CTopLevelWindow_OnClipUpdated_Org{ nullptr }; - decltype(&MyCWindowList_UpdateAccentBlurRect) g_CWindowList_UpdateAccentBlurRect_Org{ nullptr }; - - size_t g_captureRef{ 0 }; - std::vector> g_geometryBuffer{}; - - ULONGLONG g_oldBackdropBlurCachingThrottleQPCTimeDelta{ 0ull }; - bool g_disableOnBattery{ TRUE }; - bool g_overrideAccent{ FALSE }; - bool g_batteryMode{ false }; - bool g_transparencyEnabled{ true }; - FORCEINLINE bool IsBackdropAllowed() - { - if (g_batteryMode && g_disableOnBattery) - { - return false; - } - if (!g_transparencyEnabled) - { - return false; - } - return true; - } + uDwm::CTopLevelWindow* g_capturedWindow{ nullptr }; + uDwm::CRenderDataVisual* g_accentRenderDataVisual{ nullptr }; + DWORD g_accentState{}; + int g_roundRectRadius{}; } -BackdropManager::CompositedBackdropKind GlassFramework::GetActualBackdropKind(uDwm::CTopLevelWindow* This) +HRGN WINAPI GlassFramework::MyCreateRoundRectRgn(int x1, int y1, int x2, int y2, int w, int h) { - auto backgroundType{ BackdropManager::CompositedBackdropKind::Legacy }; - auto windowData{ This->GetData() }; - - if (os::buildNumber < os::build_w11_21h2) - { - backgroundType = windowData ? - (windowData->GetAccentPolicy()->IsActive() ? BackdropManager::CompositedBackdropKind::Accent : BackdropManager::CompositedBackdropKind::Legacy) : - BackdropManager::CompositedBackdropKind::Legacy; - } - else if (os::buildNumber < os::build_w11_22h2) - { - backgroundType = windowData ? - ( - *reinterpret_cast(reinterpret_cast(windowData) + 204) ? - BackdropManager::CompositedBackdropKind::SystemBackdrop : - ( - windowData->GetAccentPolicy()->IsActive() ? - BackdropManager::CompositedBackdropKind::Accent : - BackdropManager::CompositedBackdropKind::Legacy - ) - ) : - BackdropManager::CompositedBackdropKind::Legacy; - } - else + if (g_roundRectRadius == -1) { - auto calculatedBackdropType{ g_CTopLevelWindow_CalculateBackgroundType_Org(This) }; - if (calculatedBackdropType == 2 || calculatedBackdropType == 3) - { - backgroundType = BackdropManager::CompositedBackdropKind::SystemBackdrop; - } - else if (calculatedBackdropType == 4 || calculatedBackdropType == 0) - { - backgroundType = BackdropManager::CompositedBackdropKind::Legacy; - } - else - { - backgroundType = BackdropManager::CompositedBackdropKind::Accent; - } + return g_CreateRoundRectRgn_Org(x1, y1, x2, y2, w, h); } - if (!g_overrideAccent && backgroundType == BackdropManager::CompositedBackdropKind::Accent) - { - backgroundType = BackdropManager::CompositedBackdropKind::Legacy; - } - return backgroundType; + return g_CreateRoundRectRgn_Org(x1, y1, x2, y2, g_roundRectRadius, g_roundRectRadius); } -// record the geometry that has been used in the creation of draw-geometry-instruction +// restore the blur region set by DwmEnableBlurBehind and make sure the region isn't overlap with the non client region HRESULT STDMETHODCALLTYPE GlassFramework::MyCDrawGeometryInstruction_Create(uDwm::CBaseLegacyMilBrushProxy* brush, uDwm::CBaseGeometryProxy* geometry, uDwm::CDrawGeometryInstruction** instruction) { - if (g_captureRef) + if (g_capturedWindow) { - winrt::com_ptr referencedGeometry{ nullptr }; - winrt::copy_from_abi(referencedGeometry, geometry); - g_geometryBuffer.push_back(referencedGeometry); + HRGN region{ GeometryRecorder::GetRegionFromGeometry(geometry) }; + RECT rgnBox{}; + if (GetRgnBox(region, &rgnBox) != NULLREGION && !IsRectEmpty(&rgnBox)) + { + winrt::com_ptr rgnGeometry{ nullptr }; + uDwm::ResourceHelper::CreateGeometryFromHRGN(region, rgnGeometry.put()); + winrt::com_ptr solidBrush{ nullptr }; + RETURN_IF_FAILED( + uDwm::CDesktopManager::s_pDesktopManagerInstance->GetCompositor()->CreateSolidColorLegacyMilBrushProxy( + solidBrush.put() + ) + ); + auto color{ g_capturedWindow->GetTitlebarColorizationParameters()->getArgbcolor() }; + color.a *= 0.99f; + RETURN_IF_FAILED(solidBrush->Update(1.0, color)); + return g_CDrawGeometryInstruction_Create_Org(solidBrush.get(), rgnGeometry.get(), instruction); + } } return g_CDrawGeometryInstruction_Create_Org(brush, geometry, instruction); } -// record the titlebar and border region -// and make the legacy titlebar transparent + +// convert the draw geometry instruction into draw glass instruction +// and make sure the borders are splitted to improve performance HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_UpdateNCAreaBackground(uDwm::CTopLevelWindow* This) { - if (!IsBackdropAllowed()) + if (!GlassSharedData::IsBackdropAllowed()) { return g_CTopLevelWindow_UpdateNCAreaBackground_Org(This); } auto data{ This->GetData() }; - if (!data || !data->IsWindowVisibleAndUncloaked() || This->IsTrullyMinimized()) + if (!data) { - BackdropManager::Trim(This); return g_CTopLevelWindow_UpdateNCAreaBackground_Org(This); } HRESULT hr{ S_OK }; - winrt::com_ptr backdrop{ BackdropManager::GetOrCreate(This) }; - if (This->HasNonClientBackground()) { GeometryRecorder::BeginCapture(); @@ -173,23 +111,18 @@ HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_UpdateNCAreaBackgrou if (SUCCEEDED(hr)) { - backdrop = BackdropManager::GetOrCreate(This, true); + auto legacyVisualOverride{ VisualManager::GetOrCreateLegacyVisualOverrider(This, true) }; // the titlebar region has been updated // let's update our backdrop region - if (GeometryRecorder::GetGeometryCount() && backdrop) + if (GeometryRecorder::GetGeometryCount() && legacyVisualOverride) { - auto borderGeometry{ This->GetBorderGeometry() }; auto captionGeometry{ This->GetCaptionGeometry() }; - - HRGN borderRegion{ GeometryRecorder::GetRegionFromGeometry(borderGeometry) }; - HRGN captionRegion{ GeometryRecorder::GetRegionFromGeometry(captionGeometry) }; - wil::unique_hrgn realBorderRegion{ CreateRectRgn(0, 0, 0, 0) }; - wil::unique_hrgn emptyRegion{ CreateRectRgn(0, 0, 0, 0) }; - - backdrop->SetBorderRegion(borderRegion); - backdrop->SetCaptionRegion(captionRegion); + auto borderGeometry{ This->GetBorderGeometry() }; - This->GetLegacyVisual()->ClearInstructions(); + HRGN captionRegion{ GeometryRecorder::GetRegionFromGeometry(captionGeometry) }; + HRGN borderRegion{ GeometryRecorder::GetRegionFromGeometry(borderGeometry) }; + + hr = legacyVisualOverride->UpdateNCBackground(captionRegion, borderRegion); } } @@ -197,149 +130,139 @@ HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_UpdateNCAreaBackgrou } else { - backdrop = BackdropManager::GetOrCreate(This, GetActualBackdropKind(This) != BackdropManager::CompositedBackdropKind::Legacy); hr = g_CTopLevelWindow_UpdateNCAreaBackground_Org(This); - - // let's update our backdrop region - if (SUCCEEDED(hr) && backdrop) - { - wil::unique_hrgn emptyRegion{ CreateRectRgn(0, 0, 0, 0) }; - backdrop->SetBorderRegion(emptyRegion.get()); - backdrop->SetCaptionRegion(emptyRegion.get()); - } - else + auto legacyVisualOverride{ VisualManager::GetOrCreateLegacyVisualOverrider(This) }; + if (legacyVisualOverride) { - BackdropManager::Trim(This); + hr = legacyVisualOverride->UpdateNCBackground(nullptr, nullptr); } } - if (backdrop) - { - backdrop->UpdateNCBackground(); - backdrop->ValidateVisual(); - } - return hr; } -// make the visual of DwmEnableBlurBehind invisible -// and record the blur region +// make the visual of DwmEnableBlurBehind visible HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_UpdateClientBlur(uDwm::CTopLevelWindow* This) { - if (!IsBackdropAllowed()) + if (!GlassSharedData::IsBackdropAllowed()) { return g_CTopLevelWindow_UpdateClientBlur_Org(This); } auto data{ This->GetData() }; - if (!data || !data->IsWindowVisibleAndUncloaked() || This->IsTrullyMinimized()) + if (!data) { - BackdropManager::Trim(This); return g_CTopLevelWindow_UpdateClientBlur_Org(This); } + g_capturedWindow = This; GeometryRecorder::BeginCapture(); - g_captureRef += 1; - HRESULT hr{ g_CTopLevelWindow_UpdateClientBlur_Org(This) }; - if (SUCCEEDED(hr)) - { - // the dwmblurregion is updated - // UpdateClientBlur will only create at most one geometry draw instrution - if (!g_geometryBuffer.empty()) - { - HRGN clientBlurRegion{ GeometryRecorder::GetRegionFromGeometry(g_geometryBuffer.back().get())}; - RECT clientBlurBox{}; - // let's update our backdrop region - auto backdrop{ BackdropManager::GetOrCreate(This, GetRgnBox(clientBlurRegion, &clientBlurBox) != NULLREGION && !IsRectEmpty(&clientBlurBox), true) }; - if (backdrop) - { - backdrop->SetClientBlurRegion(clientBlurRegion); - backdrop->ValidateVisual(); - } - - This->GetClientBlurVisual()->ClearInstructions(); - } - } - - g_captureRef -= 1; - g_geometryBuffer.clear(); GeometryRecorder::EndCapture(); + g_capturedWindow = nullptr; return hr; } -// update the glass reflection and other stuff -HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_ValidateVisual(uDwm::CTopLevelWindow* This) +// convert accent_state=3 or 4 into 2 and replace its solid rectangle instruction into draw glass instruction +HRESULT STDMETHODCALLTYPE GlassFramework::MyCAccent_UpdateAccentPolicy(uDwm::CAccent* This, LPCRECT lprc, uDwm::ACCENT_POLICY* policy, uDwm::CBaseGeometryProxy* geometry) { - if (!IsBackdropAllowed()) + if (!GlassSharedData::IsBackdropAllowed()) { - return g_CTopLevelWindow_ValidateVisual_Org(This); + return g_CAccent_UpdateAccentPolicy_Org(This, lprc, policy, geometry); } - auto data{ This->GetData() }; - if (!data || !data->IsWindowVisibleAndUncloaked() || This->IsTrullyMinimized()) + if (!GlassSharedData::g_overrideAccent) { - BackdropManager::Trim(This); - return g_CTopLevelWindow_ValidateVisual_Org(This); + return g_CAccent_UpdateAccentPolicy_Org(This, lprc, policy, geometry); } - auto kind{ static_cast(GetActualBackdropKind(This)) }; - auto accentPolicy{ data->GetAccentPolicy() }; - auto oldAccentState{ accentPolicy->AccentState }; + HRESULT hr{ S_OK }; + auto accentPolicy{ *policy }; + if (accentPolicy.AccentState == 3 || accentPolicy.AccentState == 4) + { + accentPolicy.AccentState = 2; + hr = g_CAccent_UpdateAccentPolicy_Org(This, lprc, &accentPolicy, geometry); + accentPolicy.AccentState = policy->AccentState; + } + else + { + hr = g_CAccent_UpdateAccentPolicy_Org(This, lprc, policy, geometry); + } - if (kind == BackdropManager::CompositedBackdropKind::Accent) { accentPolicy->AccentState = 0; } - HRESULT hr{ g_CTopLevelWindow_ValidateVisual_Org(This) }; - if (kind == BackdropManager::CompositedBackdropKind::Accent) { accentPolicy->AccentState = oldAccentState; } + return hr; +} - if (SUCCEEDED(hr)) +HRESULT STDMETHODCALLTYPE GlassFramework::MyCAccent__UpdateSolidFill(uDwm::CAccent* This, uDwm::CRenderDataVisual* visual, DWORD color, const D2D1_RECT_F* lprc, float opacity) +{ + if (!GlassSharedData::IsBackdropAllowed()) + { + return g_CAccent__UpdateSolidFill_Org(This, visual, color, lprc, opacity); + } + if (!GlassSharedData::g_overrideAccent) + { + return g_CAccent__UpdateSolidFill_Org(This, visual, color, lprc, opacity); + } + if (!This->GetHwnd()) { - auto backdrop{ BackdropManager::GetOrCreate(This) }; - if (backdrop) + return g_CAccent__UpdateSolidFill_Org(This, visual, color, lprc, opacity); + } + uDwm::CWindowData* data{ nullptr }; + { + auto lock{ wil::EnterCriticalSection(uDwm::CDesktopManager::s_csDwmInstance) }; + if (FAILED(uDwm::CDesktopManager::s_pDesktopManagerInstance->GetWindowList()->GetSyncedWindowDataByHwnd(This->GetHwnd(), &data)) || !data) { - // update existing backdrop - backdrop->ValidateVisual(); + return g_CAccent__UpdateSolidFill_Org(This, visual, color, lprc, opacity); } } + g_accentState = data->GetAccentPolicy()->AccentState; + if (g_accentState != 3 && g_accentState != 4) + { + return g_CAccent__UpdateSolidFill_Org(This, visual, color, lprc, opacity); + } + + HRESULT hr{ S_OK }; + g_accentRenderDataVisual = visual; + hr = g_CAccent__UpdateSolidFill_Org(This, visual, color, lprc, opacity); + g_accentRenderDataVisual = nullptr; return hr; } -// trick dwm into thinking the accent is gone -HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_UpdateAccent(uDwm::CTopLevelWindow* This, bool visibleAndUncloaked) +HRESULT STDMETHODCALLTYPE GlassFramework::MyCRenderDataVisual_AddInstruction(uDwm::CRenderDataVisual* This, uDwm::CRenderDataInstruction* instruction) { - if (!IsBackdropAllowed()) + if (!GlassSharedData::IsBackdropAllowed()) { - return g_CTopLevelWindow_UpdateAccent_Org(This, visibleAndUncloaked); + return g_CRenderDataVisual_AddInstruction_Org(This, instruction); } - auto data{ This->GetData() }; - if (!data || !data->IsWindowVisibleAndUncloaked() || This->IsTrullyMinimized()) + if (!GlassSharedData::g_overrideAccent) { - BackdropManager::Trim(This); - return g_CTopLevelWindow_UpdateAccent_Org(This, visibleAndUncloaked); + return g_CRenderDataVisual_AddInstruction_Org(This, instruction); } - - auto kind{ static_cast(GetActualBackdropKind(This)) }; - HRESULT hr{ S_OK }; - if (kind == BackdropManager::CompositedBackdropKind::Accent) + if (g_accentRenderDataVisual != This) { - auto accentPolicy{ data->GetAccentPolicy() }; - auto oldAccentState{ accentPolicy->AccentState }; - - accentPolicy->AccentState = 0; - hr = g_CTopLevelWindow_UpdateAccent_Org(This, visibleAndUncloaked); - accentPolicy->AccentState = oldAccentState; - - winrt::com_ptr backdrop{ BackdropManager::GetOrCreate(This, kind == BackdropManager::CompositedBackdropKind::Accent) }; - if (backdrop) - { - backdrop->ValidateVisual(); - } + return g_CRenderDataVisual_AddInstruction_Org(This, instruction); } - else + + auto drawRectangleInstruction{ reinterpret_cast(instruction) }; + auto rectangle{ drawRectangleInstruction->GetRectangle() }; + auto color{ drawRectangleInstruction->GetColor() }; + if (g_accentState == 4 && color.a == 0.f) { - hr = g_CTopLevelWindow_UpdateAccent_Org(This, visibleAndUncloaked); + return g_CRenderDataVisual_AddInstruction_Org(This, instruction); } + color.a *= 0.99f; + winrt::com_ptr rgnGeometry{ nullptr }; + uDwm::ResourceHelper::CreateGeometryFromHRGN(wil::unique_hrgn{ CreateRectRgn(static_cast(rectangle.left), static_cast(rectangle.top), static_cast(rectangle.right), static_cast(rectangle.bottom)) }.get(), rgnGeometry.put()); + winrt::com_ptr solidBrush{ nullptr }; + RETURN_IF_FAILED( + uDwm::CDesktopManager::s_pDesktopManagerInstance->GetCompositor()->CreateSolidColorLegacyMilBrushProxy( + solidBrush.put() + ) + ); + RETURN_IF_FAILED(solidBrush->Update(1.0, color)); + winrt::com_ptr drawInstruction{ nullptr }; + RETURN_IF_FAILED(uDwm::CDrawGeometryInstruction::Create(solidBrush.get(), rgnGeometry.get(), drawInstruction.put())); - return hr; + return g_CRenderDataVisual_AddInstruction_Org(This, drawInstruction.get()); } // we trick dwm into thinking the window is using legacy nonclient background @@ -355,7 +278,7 @@ enum class BackgroundType */ DWORD STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_CalculateBackgroundType(uDwm::CTopLevelWindow* This) { - if (!IsBackdropAllowed()) + if (!GlassSharedData::IsBackdropAllowed()) { return g_CTopLevelWindow_CalculateBackgroundType_Org(This); } @@ -372,14 +295,13 @@ DWORD STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_CalculateBackgroundTyp // trick dwm into thinking the system backdrop is not exist HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_UpdateSystemBackdropVisual(uDwm::CTopLevelWindow* This) { - if (!IsBackdropAllowed()) + if (!GlassSharedData::IsBackdropAllowed()) { return g_CTopLevelWindow_UpdateSystemBackdropVisual_Org(This); } auto data{ This->GetData() }; - if (!data || !data->IsWindowVisibleAndUncloaked() || This->IsTrullyMinimized()) + if (!data) { - BackdropManager::Trim(This); return g_CTopLevelWindow_UpdateSystemBackdropVisual_Org(This); } @@ -396,145 +318,28 @@ HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_UpdateSystemBackdrop // release resources void STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_Destructor(uDwm::CTopLevelWindow* This) { - BackdropManager::Remove(This, true); + VisualManager::RemoveLegacyVisualOverrider(This); g_CTopLevelWindow_Destructor_Org(This); } -// thumbnail/aero peek -HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_InitializeVisualTreeClone(uDwm::CTopLevelWindow* This, uDwm::CTopLevelWindow* window, UINT cloneOptions) -{ - HRESULT hr{ g_CTopLevelWindow_InitializeVisualTreeClone_Org(This, window, cloneOptions) }; - - if (SUCCEEDED(hr)) - { - BackdropManager::TryClone(This, window); - } - return hr; -} -HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_CloneVisualTree(uDwm::CTopLevelWindow* This, uDwm::CTopLevelWindow** window, bool unknown) -{ - HRESULT hr{ g_CTopLevelWindow_CloneVisualTree_Org(This, window, unknown) }; - - if (SUCCEEDED(hr) && window && *window) - { - BackdropManager::TryClone(This, *window); - } - return hr; -} -HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_CloneVisualTree_Pre1903(uDwm::CTopLevelWindow* This, uDwm::CTopLevelWindow** window, bool unknown1, bool unknown2, bool unknown3) -{ - HRESULT hr{ g_CTopLevelWindow_CloneVisualTree_Pre1903_Org(This, window, unknown1, unknown2, unknown3) }; - - if (SUCCEEDED(hr) && window && *window) - { - BackdropManager::TryClone(This, *window); - } - return hr; -} - -// some apps may call SetWindowRgn to restrict accent blur region -HRESULT STDMETHODCALLTYPE GlassFramework::MyCTopLevelWindow_OnClipUpdated(uDwm::CTopLevelWindow* This) -{ - if (!IsBackdropAllowed()) - { - return g_CTopLevelWindow_OnClipUpdated_Org(This); - } - auto data{ This->GetData() }; - if (!data || !data->IsWindowVisibleAndUncloaked() || This->IsTrullyMinimized()) - { - BackdropManager::Trim(This); - return g_CTopLevelWindow_OnClipUpdated_Org(This); - } - - HRESULT hr{ g_CTopLevelWindow_OnClipUpdated_Org(This) }; - - if (SUCCEEDED(hr)) - { - auto kind{ static_cast(GetActualBackdropKind(This)) }; - winrt::com_ptr backdrop{ BackdropManager::GetOrCreate(This, kind == BackdropManager::CompositedBackdropKind::Accent) }; - if (backdrop) - { - wil::unique_hrgn clipRgn{ CreateRectRgn(0, 0, 0, 0) }; - if (GetWindowRgn(data->GetHwnd(), clipRgn.get()) != ERROR) - { - backdrop->SetGdiWindowRegion(clipRgn.get()); - } - else - { - backdrop->SetGdiWindowRegion(nullptr); - } - - backdrop->ValidateVisual(); - } - } - return hr; -} - -// some apps may call DwmpUpdateAccentBlurRect to restrict accent blur region -HRESULT STDMETHODCALLTYPE GlassFramework::MyCWindowList_UpdateAccentBlurRect(uDwm::CWindowList* This, const MILCMD_DWM_REDIRECTION_ACCENTBLURRECTUPDATE* milCmd) -{ - if (!IsBackdropAllowed()) - { - return g_CWindowList_UpdateAccentBlurRect_Org(This, milCmd); - } - - HRESULT hr{ g_CWindowList_UpdateAccentBlurRect_Org(This, milCmd) }; - - uDwm::CWindowData* data{ nullptr }; - uDwm::CTopLevelWindow* window{ nullptr }; - auto lock{ wil::EnterCriticalSection(uDwm::CDesktopManager::s_csDwmInstance) }; - if (SUCCEEDED(hr) && SUCCEEDED(This->GetSyncedWindowDataByHwnd(milCmd->GetHwnd(), &data)) && data && (window = data->GetWindow())) - { - auto kind{ static_cast(GetActualBackdropKind(window)) }; - auto lprc{ milCmd->GetRect() }; - if ( - lprc && - ( - lprc->right <= lprc->left || - lprc->bottom <= lprc->top - ) - ) - { - lprc = nullptr; - } - winrt::com_ptr backdrop{ BackdropManager::GetOrCreateForAccentBlurRect(window, lprc, kind == BackdropManager::CompositedBackdropKind::Accent && lprc) }; - if (backdrop) - { - backdrop->SetAccentRect(lprc); - backdrop->ValidateVisual(); - } - } - return hr; -} - void GlassFramework::UpdateConfiguration(ConfigurationFramework::UpdateType type) { if (type & ConfigurationFramework::UpdateType::Framework) { - g_disableOnBattery = static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"DisableGlassOnBattery", TRUE)); - g_batteryMode = Utils::IsBatterySaverEnabled(); + GlassSharedData::g_disableOnBattery = static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"DisableGlassOnBattery", TRUE)); + GlassSharedData::g_batteryMode = Utils::IsBatterySaverEnabled(); } if (type & ConfigurationFramework::UpdateType::Backdrop) { - g_transparencyEnabled = Utils::IsTransparencyEnabled(ConfigurationFramework::GetPersonalizeKey()); - BackdropManager::Configuration::g_roundRectRadius = static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"RoundRectRadius")); - g_overrideAccent = static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"GlassOverrideAccent")); - - WCHAR reflectionTexturePath[MAX_PATH + 1]{}; - ConfigurationFramework::DwmGetStringFromHKCUAndHKLM(L"CustomThemeReflection", reflectionTexturePath); - - BackdropManager::Configuration::g_forceAccentColorization = static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"ForceAccentColorization")); - if (BackdropManager::Configuration::g_forceAccentColorization) - { - BackdropManager::Configuration::g_accentColor = ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"AccentColor"); - BackdropManager::Configuration::g_accentColorInactive = ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"AccentColorInactive"); - } + GlassSharedData::g_transparencyEnabled = Utils::IsTransparencyEnabled(ConfigurationFramework::GetPersonalizeKey()); + GlassSharedData::g_overrideAccent = static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"GlassOverrideAccent")); + g_roundRectRadius = static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"RoundRectRadius")); } auto lock{ wil::EnterCriticalSection(uDwm::CDesktopManager::s_csDwmInstance) }; - if (!IsBackdropAllowed()) + if (!GlassSharedData::IsBackdropAllowed()) { - BackdropManager::Shutdown(); + VisualManager::ShutdownLegacyVisualOverrider(); } else { @@ -544,17 +349,13 @@ void GlassFramework::UpdateConfiguration(ConfigurationFramework::UpdateType type for (auto i{ windowList->Blink }; i != windowList; i = i->Blink) { auto data{ reinterpret_cast(i) }; - if (!data->IsWindowVisibleAndUncloaked()) { continue; } auto hwnd{ data->GetHwnd() }; if (!hwnd || !IsWindow(hwnd)) { continue; } auto window{ data->GetWindow() }; - if (!window || window->IsTrullyMinimized()) { continue; } + if (!window) { continue; } - auto backdrop{ BackdropManager::GetOrCreate(window, window->HasNonClientBackground() || GetActualBackdropKind(window) == BackdropManager::CompositedBackdropKind::Accent) }; - if (backdrop) - { - backdrop->ValidateVisual(); - } + VisualManager::RedrawTopLevelWindow(window); + LOG_IF_FAILED(window->ValidateVisual()); } } } @@ -564,40 +365,25 @@ HRESULT GlassFramework::Startup() uDwm::GetAddressFromSymbolMap("CDrawGeometryInstruction::Create", g_CDrawGeometryInstruction_Create_Org); uDwm::GetAddressFromSymbolMap("CTopLevelWindow::UpdateNCAreaBackground", g_CTopLevelWindow_UpdateNCAreaBackground_Org); uDwm::GetAddressFromSymbolMap("CTopLevelWindow::UpdateClientBlur", g_CTopLevelWindow_UpdateClientBlur_Org); - uDwm::GetAddressFromSymbolMap("CTopLevelWindow::ValidateVisual", g_CTopLevelWindow_ValidateVisual_Org); - uDwm::GetAddressFromSymbolMap("CTopLevelWindow::UpdateAccent", g_CTopLevelWindow_UpdateAccent_Org); + uDwm::GetAddressFromSymbolMap("CAccent::UpdateAccentPolicy", g_CAccent_UpdateAccentPolicy_Org); + uDwm::GetAddressFromSymbolMap("CAccent::_UpdateSolidFill", g_CAccent__UpdateSolidFill_Org); + uDwm::GetAddressFromSymbolMap("CRenderDataVisual::AddInstruction", g_CRenderDataVisual_AddInstruction_Org); uDwm::GetAddressFromSymbolMap("CTopLevelWindow::CalculateBackgroundType", g_CTopLevelWindow_CalculateBackgroundType_Org); uDwm::GetAddressFromSymbolMap("CTopLevelWindow::UpdateSystemBackdropVisual", g_CTopLevelWindow_UpdateSystemBackdropVisual_Org); uDwm::GetAddressFromSymbolMap("CTopLevelWindow::~CTopLevelWindow", g_CTopLevelWindow_Destructor_Org); - uDwm::GetAddressFromSymbolMap("CTopLevelWindow::InitializeVisualTreeClone", g_CTopLevelWindow_InitializeVisualTreeClone_Org); - uDwm::GetAddressFromSymbolMap("CTopLevelWindow::CloneVisualTree", g_CTopLevelWindow_CloneVisualTree_Org); - uDwm::GetAddressFromSymbolMap("CTopLevelWindow::CloneVisualTree", g_CTopLevelWindow_CloneVisualTree_Pre1903_Org); - uDwm::GetAddressFromSymbolMap("CTopLevelWindow::OnClipUpdated", g_CTopLevelWindow_OnClipUpdated_Org); - uDwm::GetAddressFromSymbolMap("CWindowList::UpdateAccentBlurRect", g_CWindowList_UpdateAccentBlurRect_Org); + + g_CreateRoundRectRgn_Org = reinterpret_cast(HookHelper::WriteIAT(uDwm::g_moduleHandle, "gdi32.dll", "CreateRoundRectRgn", MyCreateRoundRectRgn)); + return HookHelper::Detours::Write([]() { HookHelper::Detours::Attach(&g_CDrawGeometryInstruction_Create_Org, MyCDrawGeometryInstruction_Create); HookHelper::Detours::Attach(&g_CTopLevelWindow_UpdateNCAreaBackground_Org, MyCTopLevelWindow_UpdateNCAreaBackground); HookHelper::Detours::Attach(&g_CTopLevelWindow_UpdateClientBlur_Org, MyCTopLevelWindow_UpdateClientBlur); - HookHelper::Detours::Attach(&g_CTopLevelWindow_ValidateVisual_Org, MyCTopLevelWindow_ValidateVisual); - HookHelper::Detours::Attach(&g_CTopLevelWindow_UpdateAccent_Org, MyCTopLevelWindow_UpdateAccent); + HookHelper::Detours::Attach(&g_CAccent_UpdateAccentPolicy_Org, MyCAccent_UpdateAccentPolicy); + HookHelper::Detours::Attach(&g_CAccent__UpdateSolidFill_Org, MyCAccent__UpdateSolidFill); + HookHelper::Detours::Attach(&g_CRenderDataVisual_AddInstruction_Org, MyCRenderDataVisual_AddInstruction); HookHelper::Detours::Attach(&g_CTopLevelWindow_Destructor_Org, MyCTopLevelWindow_Destructor); - HookHelper::Detours::Attach(&g_CWindowList_UpdateAccentBlurRect_Org, MyCWindowList_UpdateAccentBlurRect); - if (os::buildNumber < os::build_w10_1903) - { - HookHelper::Detours::Attach(&g_CTopLevelWindow_CloneVisualTree_Pre1903_Org, MyCTopLevelWindow_CloneVisualTree_Pre1903); - } - else if (os::buildNumber < os::build_w10_2004) - { - HookHelper::Detours::Attach(&g_CTopLevelWindow_OnClipUpdated_Org, MyCTopLevelWindow_OnClipUpdated); - HookHelper::Detours::Attach(&g_CTopLevelWindow_CloneVisualTree_Org, MyCTopLevelWindow_CloneVisualTree); - } - else - { - HookHelper::Detours::Attach(&g_CTopLevelWindow_OnClipUpdated_Org, MyCTopLevelWindow_OnClipUpdated); - HookHelper::Detours::Attach(&g_CTopLevelWindow_InitializeVisualTreeClone_Org, MyCTopLevelWindow_InitializeVisualTreeClone); - } if (os::buildNumber == os::build_w11_21h2) { HookHelper::Detours::Attach(&g_CTopLevelWindow_UpdateSystemBackdropVisual_Org, MyCTopLevelWindow_UpdateSystemBackdropVisual); @@ -616,24 +402,10 @@ void GlassFramework::Shutdown() HookHelper::Detours::Detach(&g_CDrawGeometryInstruction_Create_Org, MyCDrawGeometryInstruction_Create); HookHelper::Detours::Detach(&g_CTopLevelWindow_UpdateNCAreaBackground_Org, MyCTopLevelWindow_UpdateNCAreaBackground); HookHelper::Detours::Detach(&g_CTopLevelWindow_UpdateClientBlur_Org, MyCTopLevelWindow_UpdateClientBlur); - HookHelper::Detours::Detach(&g_CTopLevelWindow_ValidateVisual_Org, MyCTopLevelWindow_ValidateVisual); - HookHelper::Detours::Detach(&g_CTopLevelWindow_UpdateAccent_Org, MyCTopLevelWindow_UpdateAccent); + HookHelper::Detours::Detach(&g_CAccent_UpdateAccentPolicy_Org, MyCAccent_UpdateAccentPolicy); + HookHelper::Detours::Detach(&g_CAccent__UpdateSolidFill_Org, MyCAccent__UpdateSolidFill); + HookHelper::Detours::Detach(&g_CRenderDataVisual_AddInstruction_Org, MyCRenderDataVisual_AddInstruction); HookHelper::Detours::Detach(&g_CTopLevelWindow_Destructor_Org, MyCTopLevelWindow_Destructor); - HookHelper::Detours::Detach(&g_CWindowList_UpdateAccentBlurRect_Org, MyCWindowList_UpdateAccentBlurRect); - if (os::buildNumber < os::build_w10_1903) - { - HookHelper::Detours::Detach(&g_CTopLevelWindow_CloneVisualTree_Pre1903_Org, MyCTopLevelWindow_CloneVisualTree_Pre1903); - } - else if (os::buildNumber < os::build_w10_2004) - { - HookHelper::Detours::Detach(&g_CTopLevelWindow_OnClipUpdated_Org, MyCTopLevelWindow_OnClipUpdated); - HookHelper::Detours::Detach(&g_CTopLevelWindow_CloneVisualTree_Org, MyCTopLevelWindow_CloneVisualTree); - } - else - { - HookHelper::Detours::Detach(&g_CTopLevelWindow_OnClipUpdated_Org, MyCTopLevelWindow_OnClipUpdated); - HookHelper::Detours::Detach(&g_CTopLevelWindow_InitializeVisualTreeClone_Org, MyCTopLevelWindow_InitializeVisualTreeClone); - } if (os::buildNumber == os::build_w11_21h2) { HookHelper::Detours::Detach(&g_CTopLevelWindow_UpdateSystemBackdropVisual_Org, MyCTopLevelWindow_UpdateSystemBackdropVisual); @@ -643,7 +415,26 @@ void GlassFramework::Shutdown() HookHelper::Detours::Detach(&g_CTopLevelWindow_CalculateBackgroundType_Org, MyCTopLevelWindow_CalculateBackgroundType); } }); - g_captureRef = 0; - g_geometryBuffer.clear(); - BackdropManager::Shutdown(); + + if (g_CreateRoundRectRgn_Org) + { + HookHelper::WriteIAT(uDwm::g_moduleHandle, "gdi32.dll", "CreateRoundRectRgn", g_CreateRoundRectRgn_Org); + } + + g_capturedWindow = nullptr; + VisualManager::ShutdownLegacyVisualOverrider(); + ULONG_PTR desktopID{ 0 }; + Utils::GetDesktopID(1, &desktopID); + auto windowList{ uDwm::CDesktopManager::s_pDesktopManagerInstance->GetWindowList()->GetWindowListForDesktop(desktopID) }; + for (auto i{ windowList->Blink }; i != windowList; i = i->Blink) + { + auto data{ reinterpret_cast(i) }; + auto hwnd{ data->GetHwnd() }; + if (!hwnd || !IsWindow(hwnd)) { continue; } + auto window{ data->GetWindow() }; + if (!window) { continue; } + + VisualManager::RedrawTopLevelWindow(window); + LOG_IF_FAILED(window->ValidateVisual()); + } } \ No newline at end of file diff --git a/OpenGlass/GlassRenderer.cpp b/OpenGlass/GlassRenderer.cpp new file mode 100644 index 0000000..47bc054 --- /dev/null +++ b/OpenGlass/GlassRenderer.cpp @@ -0,0 +1,321 @@ +#include "pch.h" +#include "HookHelper.hpp" +#include "uDwmProjection.hpp" +#include "dwmcoreProjection.hpp" +#include "GlassRenderer.hpp" +#include "GlassEffectManager.hpp" +#include "GlassSharedData.hpp" +#include "ReflectionRenderer.hpp" + +using namespace OpenGlass; + +namespace OpenGlass::GlassRenderer +{ + HRESULT STDMETHODCALLTYPE MyCRenderData_TryDrawCommandAsDrawList( + dwmcore::CResource* This, + dwmcore::CDrawingContext* drawingContext, + dwmcore::CDrawListCache* drawListCache, + dwmcore::CResource* drawListEntryBuilder, + bool unknwon, + int commandType, + dwmcore::CResource** resources, + bool* succeeded + ); + HRESULT STDMETHODCALLTYPE MyCRenderData_DrawSolidColorRectangle( + dwmcore::CResource* This, + dwmcore::CDrawingContext* drawingContext, + dwmcore::CResource* drawListEntryBuilder, + bool unknwon, + const D2D1_RECT_F& lprc, + const D2D1_COLOR_F& color + ); + HRESULT STDMETHODCALLTYPE MyCDrawingContext_DrawGeometry( + dwmcore::IDrawingContext* This, + dwmcore::CLegacyMilBrush* brush, + dwmcore::CGeometry* geometry + ); + void STDMETHODCALLTYPE MyID2D1DeviceContext_FillGeometry( + ID2D1DeviceContext* This, + ID2D1Geometry* geometry, + ID2D1Brush* brush, + ID2D1Brush* opacityBrush + ); + void STDMETHODCALLTYPE MyCGeometry_Destructor(dwmcore::CGeometry* This); + HRESULT STDMETHODCALLTYPE MyCDirtyRegion__Add( + dwmcore::CDirtyRegion* This, + dwmcore::CVisual* visual, + bool unknown, + const D2D1_RECT_F& lprc + ); + + decltype(&MyCRenderData_TryDrawCommandAsDrawList) g_CRenderData_TryDrawCommandAsDrawList_Org{ nullptr }; + decltype(&MyCRenderData_DrawSolidColorRectangle) g_CRenderData_DrawSolidColorRectangle_Org{ nullptr }; + decltype(&MyCDrawingContext_DrawGeometry) g_CDrawingContext_DrawGeometry_Org{ nullptr }; + decltype(&MyCDrawingContext_DrawGeometry)* g_CDrawingContext_DrawGeometry_Org_Address{ nullptr }; + decltype(&MyID2D1DeviceContext_FillGeometry) g_ID2D1DeviceContext_FillGeometry_Org{ nullptr }; + decltype(&MyID2D1DeviceContext_FillGeometry)* g_ID2D1DeviceContext_FillGeometry_Org_Address{ nullptr }; + decltype(&MyCGeometry_Destructor) g_CGeometry_Destructor_Org{ nullptr }; + decltype(&MyCDirtyRegion__Add) g_CDirtyRegion__Add_Org{ nullptr }; + PVOID* g_CSolidColorLegacyMilBrush_vftable{ nullptr }; + + std::optional g_drawColor{}; + GlassEffectManager::IGlassEffect* g_glassEffectNoRef{ nullptr }; + dwmcore::IDrawingContext* g_drawingContextNoRef{ nullptr }; + ID2D1Device* g_deviceNoRef{ nullptr }; + + float g_blurAmount{ 9.f }; + float g_glassOpacity{ 0.63f }; +} + +HRESULT STDMETHODCALLTYPE GlassRenderer::MyCRenderData_TryDrawCommandAsDrawList( + dwmcore::CResource* This, + dwmcore::CDrawingContext* drawingContext, + dwmcore::CDrawListCache* drawListCache, + dwmcore::CResource* drawListEntryBuilder, + bool unknwon, + int commandType, + dwmcore::CResource** resources, + bool* succeeded +) +{ + g_drawColor = std::nullopt; + HRESULT hr{ g_CRenderData_TryDrawCommandAsDrawList_Org(This, drawingContext, drawListCache, drawListEntryBuilder, unknwon, commandType, resources, succeeded) }; + if (SUCCEEDED(hr) && g_drawColor) + { + *succeeded = false; + } + return hr; +} +HRESULT STDMETHODCALLTYPE GlassRenderer::MyCRenderData_DrawSolidColorRectangle( + dwmcore::CResource* This, + dwmcore::CDrawingContext* drawingContext, + dwmcore::CResource* drawListEntryBuilder, + bool unknwon, + const D2D1_RECT_F& lprc, + const D2D1_COLOR_F& color +) +{ + if ( + color.a != 1.f && + GlassSharedData::IsBackdropAllowed() + ) + { + g_drawColor = color; + + if (!g_CDrawingContext_DrawGeometry_Org) + { + g_CDrawingContext_DrawGeometry_Org_Address = reinterpret_cast(&(HookHelper::vtbl_of(drawingContext->GetInterface())[4])); + g_CDrawingContext_DrawGeometry_Org = HookHelper::WritePointer(g_CDrawingContext_DrawGeometry_Org_Address, MyCDrawingContext_DrawGeometry); + } + + return S_OK; + } + + return g_CRenderData_DrawSolidColorRectangle_Org( + This, + drawingContext, + drawListEntryBuilder, + unknwon, + lprc, + color + ); +} + +HRESULT STDMETHODCALLTYPE GlassRenderer::MyCDrawingContext_DrawGeometry( + dwmcore::IDrawingContext* This, + dwmcore::CLegacyMilBrush* brush, + dwmcore::CGeometry* geometry +) +{ + HRESULT hr{ g_CDrawingContext_DrawGeometry_Org(This, brush, geometry) }; + if ( + !brush || + !geometry || + HookHelper::vtbl_of(brush) != g_CSolidColorLegacyMilBrush_vftable || + !g_drawColor.has_value() || + g_drawColor.value().a == 1.f + ) + { + return hr; + } + + D2D1_COLOR_F color{ dwmcore::Convert_D2D1_COLOR_F_scRGB_To_D2D1_COLOR_F_sRGB(g_drawColor.value()) }; + g_drawColor = std::nullopt; + dwmcore::CShapePtr geometryShape{ nullptr, false }; + if ( + FAILED(geometry->GetShapeData(nullptr, &geometryShape)) || + !geometryShape || + geometryShape->IsEmpty() + ) + { + return hr; + } + + D2D1_RECT_F boundRect{}; + RETURN_IF_FAILED(geometryShape->GetTightBounds(&boundRect, nullptr)); + D2D1_RECT_F clippedDrawRect{}; + This->GetDrawingContext()->CalcWorldSpaceClippedBounds(boundRect, &clippedDrawRect); + if ( + clippedDrawRect.right <= clippedDrawRect.left || + clippedDrawRect.bottom <= clippedDrawRect.top || + This->GetDrawingContext()->IsOccluded(boundRect, This->GetDrawingContext()->GetD2DContextOwner()->GetCurrentZ()) + ) + { + return hr; + } + + auto deviceContext{ This->GetDrawingContext()->GetD2DContext()->GetDeviceContext() }; + winrt::com_ptr device{ nullptr }; + deviceContext->GetDevice(device.put()); + if (g_deviceNoRef != device.get()) + { + g_deviceNoRef = device.get(); + ReflectionRenderer::g_reflectionBitmap = nullptr; + GlassEffectManager::Shutdown(); + } + winrt::com_ptr glassEffect{ GlassEffectManager::GetOrCreate(geometry, deviceContext, true) }; + if (!glassEffect) + { + return hr; + } + + g_glassEffectNoRef = glassEffect.get(); + g_drawingContextNoRef = This; + if (!g_ID2D1DeviceContext_FillGeometry_Org) + { + g_ID2D1DeviceContext_FillGeometry_Org_Address = reinterpret_cast(&HookHelper::vtbl_of(This->GetDrawingContext()->GetD2DContext()->GetDeviceContext())[0x17]); + g_ID2D1DeviceContext_FillGeometry_Org = HookHelper::WritePointer(g_ID2D1DeviceContext_FillGeometry_Org_Address, MyID2D1DeviceContext_FillGeometry); + } + + dwmcore::CMILMatrix matrix{}; + D2D1_RECT_F shapeActualBounds{}; + RETURN_IF_FAILED(This->GetDrawingContext()->GetWorldTransform(&matrix)); + RETURN_IF_FAILED(geometryShape->GetTightBounds(&shapeActualBounds, &matrix)); + RETURN_IF_FAILED(glassEffect->SetSourceRect(shapeActualBounds)); + + winrt::com_ptr backdropBitmap{ nullptr }; + // This->GetDrawingContext()->GetD2DBitmap(backdropBitmap.put()); + This->GetDrawingContext()->FlushD2D(); + // hahaha, i can't belive i can actually convert ID2D1Image into ID2D1Bitmap1! + winrt::com_ptr backdropImage{}; + This->GetDrawingContext()->GetD2DContext()->GetDeviceContext()->GetTarget(backdropImage.put()); + backdropBitmap = backdropImage.as(); + + RETURN_IF_FAILED(glassEffect->Invalidate(backdropBitmap.get(), clippedDrawRect, color, g_glassOpacity, g_blurAmount)); + + hr = This->GetDrawingContext()->FillShapeWithColor(geometryShape.ptr, &color); + return hr; +} + +void STDMETHODCALLTYPE GlassRenderer::MyID2D1DeviceContext_FillGeometry( + ID2D1DeviceContext* This, + ID2D1Geometry* geometry, + ID2D1Brush* brush, + ID2D1Brush* opacityBrush +) +{ + winrt::com_ptr solidColorBrush{ nullptr }; + if ( + SUCCEEDED(brush->QueryInterface(solidColorBrush.put())) && + g_glassEffectNoRef && + g_drawingContextNoRef + ) + { + auto glassEffect{ g_glassEffectNoRef }; + g_drawingContextNoRef = nullptr; + g_glassEffectNoRef = nullptr; + + LOG_IF_FAILED(glassEffect->Render(geometry)); + return; + } + return g_ID2D1DeviceContext_FillGeometry_Org(This, geometry, brush, opacityBrush); +} + +void STDMETHODCALLTYPE GlassRenderer::MyCGeometry_Destructor(dwmcore::CGeometry* This) +{ + GlassEffectManager::Remove(This); + return g_CGeometry_Destructor_Org(This); +} + +// this is not the best way to mitigate artifacts, it needs to be reworked in the future! +HRESULT STDMETHODCALLTYPE GlassRenderer::MyCDirtyRegion__Add( + dwmcore::CDirtyRegion* This, + dwmcore::CVisual* visual, + bool unknown, + const D2D1_RECT_F& lprc +) +{ + float extendAmount{ g_blurAmount * 1.5f + 0.5f }; + D2D1_RECT_F extendedDirtyRectangle + { + lprc.left - extendAmount, + lprc.top - extendAmount, + lprc.right + extendAmount, + lprc.bottom + extendAmount + }; + return g_CDirtyRegion__Add_Org( + This, + visual, + unknown, + extendedDirtyRectangle + ); +} + +void GlassRenderer::UpdateConfiguration(ConfigurationFramework::UpdateType type) +{ + if (type & ConfigurationFramework::UpdateType::Backdrop) + { + g_blurAmount = std::clamp(static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"BlurDeviation", 30)) / 10.f * 3.f, 0.f, 250.f); + g_glassOpacity = std::clamp(static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"GlassOpacity", 63)) / 100.f, 0.f, 1.f); + WCHAR reflectionTexturePath[MAX_PATH + 1]{}; + ConfigurationFramework::DwmGetStringFromHKCUAndHKLM(L"CustomThemeReflection", reflectionTexturePath); + ReflectionRenderer::g_reflectionTexturePath = reflectionTexturePath; + ReflectionRenderer::g_reflectionIntensity = std::clamp(static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"ColorizationGlassReflectionIntensity")) / 100.f, 0.f, 1.f); + ReflectionRenderer::g_reflectionParallaxIntensity = std::clamp(static_cast(ConfigurationFramework::DwmGetDwordFromHKCUAndHKLM(L"ColorizationGlassReflectionParallaxIntensity", 10)) / 100.f, 0.f, 1.f); + ReflectionRenderer::g_reflectionBitmap = nullptr; + } +} + +HRESULT GlassRenderer::Startup() +{ + dwmcore::GetAddressFromSymbolMap("CRenderData::TryDrawCommandAsDrawList", g_CRenderData_TryDrawCommandAsDrawList_Org); + dwmcore::GetAddressFromSymbolMap("CRenderData::DrawSolidColorRectangle", g_CRenderData_DrawSolidColorRectangle_Org); + dwmcore::GetAddressFromSymbolMap("CGeometry::~CGeometry", g_CGeometry_Destructor_Org); + dwmcore::GetAddressFromSymbolMap("CSolidColorLegacyMilBrush::`vftable'", g_CSolidColorLegacyMilBrush_vftable); + dwmcore::GetAddressFromSymbolMap("CDirtyRegion::_Add", g_CDirtyRegion__Add_Org); + + return HookHelper::Detours::Write([]() + { + HookHelper::Detours::Attach(&g_CRenderData_TryDrawCommandAsDrawList_Org, MyCRenderData_TryDrawCommandAsDrawList); + HookHelper::Detours::Attach(&g_CRenderData_DrawSolidColorRectangle_Org, MyCRenderData_DrawSolidColorRectangle); + HookHelper::Detours::Attach(&g_CGeometry_Destructor_Org, MyCGeometry_Destructor); + HookHelper::Detours::Attach(&g_CDirtyRegion__Add_Org, MyCDirtyRegion__Add); + }); +} + +void GlassRenderer::Shutdown() +{ + HookHelper::Detours::Write([]() + { + HookHelper::Detours::Detach(&g_CRenderData_TryDrawCommandAsDrawList_Org, MyCRenderData_TryDrawCommandAsDrawList); + HookHelper::Detours::Detach(&g_CRenderData_DrawSolidColorRectangle_Org, MyCRenderData_DrawSolidColorRectangle); + HookHelper::Detours::Detach(&g_CGeometry_Destructor_Org, MyCGeometry_Destructor); + HookHelper::Detours::Detach(&g_CDirtyRegion__Add_Org, MyCDirtyRegion__Add); + }); + + if (g_ID2D1DeviceContext_FillGeometry_Org) + { + HookHelper::WritePointer(g_ID2D1DeviceContext_FillGeometry_Org_Address, g_ID2D1DeviceContext_FillGeometry_Org); + g_ID2D1DeviceContext_FillGeometry_Org_Address = nullptr; + g_ID2D1DeviceContext_FillGeometry_Org = nullptr; + } + if (g_CDrawingContext_DrawGeometry_Org) + { + HookHelper::WritePointer(g_CDrawingContext_DrawGeometry_Org_Address, g_CDrawingContext_DrawGeometry_Org); + g_CDrawingContext_DrawGeometry_Org_Address = nullptr; + g_CDrawingContext_DrawGeometry_Org = nullptr; + } + + GlassEffectManager::Shutdown(); + ReflectionRenderer::g_reflectionBitmap = nullptr; +} \ No newline at end of file diff --git a/OpenGlass/GlassRenderer.hpp b/OpenGlass/GlassRenderer.hpp new file mode 100644 index 0000000..45cc45b --- /dev/null +++ b/OpenGlass/GlassRenderer.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "framework.hpp" +#include "cpprt.hpp" +#include "ConfigurationFramework.hpp" + +namespace OpenGlass::GlassRenderer +{ + void UpdateConfiguration(ConfigurationFramework::UpdateType type); + + HRESULT Startup(); + void Shutdown(); +} \ No newline at end of file diff --git a/OpenGlass/GlassSharedData.hpp b/OpenGlass/GlassSharedData.hpp new file mode 100644 index 0000000..df9aa3f --- /dev/null +++ b/OpenGlass/GlassSharedData.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "framework.hpp" +#include "cpprt.hpp" + +namespace OpenGlass::GlassSharedData +{ + inline bool g_disableOnBattery{ true }; + inline bool g_overrideAccent{ false }; + inline bool g_batteryMode{ false }; + inline bool g_transparencyEnabled{ true }; + + FORCEINLINE bool IsBackdropAllowed() + { + if (g_batteryMode && g_disableOnBattery) + { + return false; + } + if (!g_transparencyEnabled) + { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/OpenGlass/OSHelper.hpp b/OpenGlass/OSHelper.hpp index a34b81b..189ff2a 100644 --- a/OpenGlass/OSHelper.hpp +++ b/OpenGlass/OSHelper.hpp @@ -189,8 +189,8 @@ namespace OpenGlass::os constexpr ULONG build_w11_21h2{ 22000 }; constexpr ULONG build_w11_22h2{ 22621 }; constexpr ULONG build_w11_23h2{ 22635 }; - constexpr ULONG build_openglass_minimum_support{ build_w10_1809 }; - constexpr ULONG build_openglass_maximum_support{ build_w11_23h2 }; + constexpr ULONG build_openglass_minimum_support{ build_w10_22h2 }; + constexpr ULONG build_openglass_maximum_support{ build_w10_22h2 }; FORCEINLINE bool IsOpenGlassUnsupported() { diff --git a/OpenGlass/OpenGlass.cpp b/OpenGlass/OpenGlass.cpp index d3aaf79..a98a86b 100644 --- a/OpenGlass/OpenGlass.cpp +++ b/OpenGlass/OpenGlass.cpp @@ -10,6 +10,7 @@ #include "GeometryRecorder.hpp" #include "CaptionTextHandler.hpp" #include "GlassFramework.hpp" +#include "GlassRenderer.hpp" #include "CustomMsstyleLoader.hpp" #include "ConfigurationFramework.hpp" @@ -419,6 +420,7 @@ DWORD WINAPI OpenGlass::Initialize(PVOID) ConfigurationFramework::Unload(); GlassFramework::Startup(); + GlassRenderer::Startup(); CaptionTextHandler::Startup(); GeometryRecorder::Startup(); CustomMsstyleLoader::Startup(); @@ -514,6 +516,7 @@ void OpenGlass::Shutdown() GeometryRecorder::Shutdown(); CaptionTextHandler::Shutdown(); + GlassRenderer::Shutdown(); GlassFramework::Shutdown(); CustomMsstyleLoader::Shutdown(); diff --git a/OpenGlass/OpenGlass.vcxproj b/OpenGlass/OpenGlass.vcxproj index 392ed1a..d2d6ee4 100644 --- a/OpenGlass/OpenGlass.vcxproj +++ b/OpenGlass/OpenGlass.vcxproj @@ -189,11 +189,15 @@ + + + + - + @@ -211,7 +215,9 @@ - + + + diff --git a/OpenGlass/ReflectionRenderer.hpp b/OpenGlass/ReflectionRenderer.hpp new file mode 100644 index 0000000..29eeba3 --- /dev/null +++ b/OpenGlass/ReflectionRenderer.hpp @@ -0,0 +1,147 @@ +#pragma once +#include "pch.h" +#include "resource.h" +#include "framework.hpp" +#include "cpprt.hpp" +#include "uDwmProjection.hpp" + +namespace OpenGlass::ReflectionRenderer +{ + inline float g_reflectionIntensity{ 0.f }; + inline float g_reflectionParallaxIntensity{ 0.1f }; + inline std::wstring g_reflectionTexturePath{}; + inline winrt::com_ptr g_reflectionBitmap{ nullptr }; + + inline HRESULT LoadReflectionTexture(ID2D1DeviceContext* deviceContext) + { + winrt::com_ptr stream{ nullptr }; + if (g_reflectionTexturePath.empty() || !PathFileExistsW(g_reflectionTexturePath.data())) + { + HMODULE currentModule{ wil::GetModuleInstanceHandle() }; + auto resourceHandle{ FindResourceW(currentModule, MAKEINTRESOURCE(IDB_REFLECTION), L"PNG") }; + RETURN_LAST_ERROR_IF_NULL(resourceHandle); + auto globalHandle{ LoadResource(currentModule, resourceHandle) }; + RETURN_LAST_ERROR_IF_NULL(globalHandle); + auto cleanUp = wil::scope_exit([&] + { + if (globalHandle) + { + UnlockResource(globalHandle); + FreeResource(globalHandle); + } + }); + DWORD resourceSize{ SizeofResource(currentModule, resourceHandle) }; + RETURN_LAST_ERROR_IF(resourceSize == 0); + auto resourceAddress{ reinterpret_cast(LockResource(globalHandle)) }; + stream = { SHCreateMemStream(resourceAddress, resourceSize), winrt::take_ownership_from_abi }; + } + else + { + wil::unique_hfile file{ CreateFileW(g_reflectionTexturePath.data(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0) }; + RETURN_LAST_ERROR_IF(!file.is_valid()); + + LARGE_INTEGER fileSize{}; + RETURN_IF_WIN32_BOOL_FALSE(GetFileSizeEx(file.get(), &fileSize)); + + auto buffer{ std::make_unique(static_cast(fileSize.QuadPart)) }; + RETURN_IF_WIN32_BOOL_FALSE(ReadFile(file.get(), buffer.get(), static_cast(fileSize.QuadPart), nullptr, nullptr)); + stream = { SHCreateMemStream(buffer.get(), static_cast(fileSize.QuadPart)), winrt::take_ownership_from_abi }; + } + RETURN_LAST_ERROR_IF_NULL(stream); + + winrt::com_ptr wicFactory{ nullptr }; + wicFactory.copy_from(uDwm::CDesktopManager::s_pDesktopManagerInstance->GetWICFactory()); + winrt::com_ptr wicDecoder{ nullptr }; + RETURN_IF_FAILED(wicFactory->CreateDecoderFromStream(stream.get(), &GUID_VendorMicrosoft, WICDecodeMetadataCacheOnDemand, wicDecoder.put())); + winrt::com_ptr wicFrame{ nullptr }; + RETURN_IF_FAILED(wicDecoder->GetFrame(0, wicFrame.put())); + winrt::com_ptr wicConverter{ nullptr }; + RETURN_IF_FAILED(wicFactory->CreateFormatConverter(wicConverter.put())); + winrt::com_ptr wicPalette{ nullptr }; + RETURN_IF_FAILED( + wicConverter->Initialize( + wicFrame.get(), + GUID_WICPixelFormat32bppPBGRA, + WICBitmapDitherTypeNone, + wicPalette.get(), + 0, WICBitmapPaletteTypeCustom + ) + ); + winrt::com_ptr wicBitmap{ nullptr }; + RETURN_IF_FAILED(wicFactory->CreateBitmapFromSource(wicConverter.get(), WICBitmapCreateCacheOption::WICBitmapNoCache, wicBitmap.put())); + + RETURN_IF_FAILED( + deviceContext->CreateBitmapFromWicBitmap( + wicBitmap.get(), + D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_NONE, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED) + ), + g_reflectionBitmap.put() + ) + ); + + return S_OK; + } + inline HRESULT Draw( + ID2D1DeviceContext* deviceContext, + const D2D1_POINT_2F& reflectionPosition, + const D2D1_SIZE_F& desktopSize, + const D2D1_RECT_F& reflectionBounds + ) + { + if (!g_reflectionBitmap) + { + RETURN_IF_FAILED(LoadReflectionTexture(deviceContext)); + } + if (g_reflectionIntensity != 0.f) + { + auto reflectionSize{ g_reflectionBitmap->GetSize() }; + auto bounds{ reflectionBounds }; + D2D1_POINT_2F offset + { + reflectionPosition.x * (1.f - g_reflectionParallaxIntensity) * (reflectionSize.width / desktopSize.width), + reflectionPosition.y * (reflectionSize.height / desktopSize.height) + }; + if (reflectionPosition.x < 0) + { + bounds.left += -reflectionPosition.x; + offset.x += -offset.x; + } + if (reflectionPosition.y < 0) + { + bounds.top += -reflectionPosition.y; + offset.y += -offset.y; + } + if (reflectionPosition.x + reflectionBounds.right - reflectionBounds.left > desktopSize.width) + { + bounds.right = bounds.right - (reflectionPosition.x + reflectionBounds.right - reflectionBounds.left - desktopSize.width); + } + if (reflectionPosition.y + reflectionBounds.bottom - reflectionBounds.top > desktopSize.height) + { + bounds.bottom = bounds.bottom - (reflectionPosition.y + reflectionBounds.bottom - reflectionBounds.top - desktopSize.height); + } + + D2D1_SIZE_F size + { + (bounds.right - bounds.left) * (reflectionSize.width / desktopSize.width), + (bounds.bottom - bounds.top) * (reflectionSize.height / desktopSize.height) + }; + + deviceContext->DrawBitmap( + g_reflectionBitmap.get(), + bounds, + g_reflectionIntensity, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + D2D1::RectF( + offset.x, + offset.y, + offset.x + size.width, + offset.y + size.height + ) + ); + } + + return S_OK; + } +} \ No newline at end of file diff --git a/OpenGlass/Utils.hpp b/OpenGlass/Utils.hpp index c581a53..60483e7 100644 --- a/OpenGlass/Utils.hpp +++ b/OpenGlass/Utils.hpp @@ -1,7 +1,6 @@ #pragma once #include "framework.hpp" #include "cpprt.hpp" -#include "winrt.hpp" #include "HookHelper.hpp" namespace OpenGlass::Utils @@ -108,49 +107,21 @@ namespace OpenGlass::Utils return static_cast(isLocalSystem); } - FORCEINLINE wu::Color FromAbgr(DWORD color) + FORCEINLINE D2D1_COLOR_F FromAbgr(DWORD color) { auto abgr{ reinterpret_cast(&color) }; return { - abgr[3], - abgr[0], - abgr[1], - abgr[2] + static_cast(abgr[0]) / 255.f, + static_cast(abgr[1]) / 255.f, + static_cast(abgr[2]) / 255.f, + static_cast(abgr[3]) / 255.f }; } - FORCEINLINE wu::Color FromArgb(DWORD color) - { - auto abgr{ reinterpret_cast(&color) }; - return - { - abgr[3], - abgr[2], - abgr[1], - abgr[0] - }; - } - - FORCEINLINE void ThisModule_AddRef() - { - HMODULE thisModule{ nullptr }; - GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, L"", &thisModule); - } - FORCEINLINE void ThisModule_Release(bool async = true) - { - if (async) - { - static wil::unique_threadpool_work s_freeModuleRefWork{ CreateThreadpoolWork([](PTP_CALLBACK_INSTANCE instance, PVOID, PTP_WORK) { DwmFlush(); FreeLibraryWhenCallbackReturns(instance, wil::GetModuleInstanceHandle()); }, nullptr, nullptr) }; - SubmitThreadpoolWork(s_freeModuleRefWork.get()); - } - else - { - FreeLibraryAndExitThread(wil::GetModuleInstanceHandle(), 0); - } - } } #define DEFINE_INVOKER(fn) static const auto s_fn_ptr{ Utils::cast_pointer(g_symbolMap.at(#fn)) } #define DEFINE_USER_INVOKER(type, name) static const auto s_fn_ptr{ Utils::cast_pointer(g_symbolMap.at(name)) } +#define DEFINE_CUSTOM_INVOKER(type, name) static const auto s_fn_ptr{ Utils::cast_pointer(g_symbolMap.at(name)) } #define INVOKE_MEMBERFUNCTION(...) std::invoke(s_fn_ptr, this, ##__VA_ARGS__) #define INVOKE_FUNCTION(...) std::invoke(s_fn_ptr, ##__VA_ARGS__) \ No newline at end of file diff --git a/OpenGlass/VisualManager.cpp b/OpenGlass/VisualManager.cpp new file mode 100644 index 0000000..6af2a18 --- /dev/null +++ b/OpenGlass/VisualManager.cpp @@ -0,0 +1,335 @@ +#include "pch.h" +#include "GlassFramework.hpp" +#include "uDwmProjection.hpp" +#include "VisualManager.hpp" +#include "Utils.hpp" + +using namespace OpenGlass; +namespace OpenGlass::VisualManager +{ + std::unordered_map> g_visualMap{}; + + class CLegacyVisualOverrider : public winrt::implements + { + bool m_initialized{ false }; + uDwm::CTopLevelWindow* m_window{ nullptr }; + winrt::com_ptr m_brush{ nullptr }; + winrt::com_ptr m_captionRgnGeometry{ nullptr }; + winrt::com_ptr m_topBorderRgnGeometry{ nullptr }; + winrt::com_ptr m_leftBorderRgnGeometry{ nullptr }; + winrt::com_ptr m_bottomBorderRgnGeometry{ nullptr }; + winrt::com_ptr m_rightBorderRgnGeometry{ nullptr }; + winrt::com_ptr m_captionDrawInstruction{ nullptr }; + winrt::com_ptr m_topBorderDrawInstruction{ nullptr }; + winrt::com_ptr m_leftBorderDrawInstruction{ nullptr }; + winrt::com_ptr m_bottomBorderDrawInstruction{ nullptr }; + winrt::com_ptr m_rightBorderDrawInstruction{ nullptr }; + + HRESULT Initialize(); + public: + CLegacyVisualOverrider(uDwm::CTopLevelWindow* window); + virtual ~CLegacyVisualOverrider(); + HRESULT STDMETHODCALLTYPE UpdateNCBackground( + HRGN captionRgn, + HRGN borderRgn + ) override; + }; + void RedrawTopLevelWindow(uDwm::CTopLevelWindow* window); +} + +void VisualManager::RedrawTopLevelWindow(uDwm::CTopLevelWindow* window) +{ + // 0x10000 UpdateText + // 0x20000 UpdateIcon + window->SetDirtyFlags(window->GetDirtyFlags() | 0x10000 | 0x20000 | 0x4000 | 0x400000); + if (os::buildNumber >= os::build_w11_21h2) + { + LOG_IF_FAILED(window->OnSystemBackdropUpdated()); + } + LOG_IF_FAILED(window->OnAccentPolicyUpdated()); + LOG_IF_FAILED(window->OnClipUpdated()); +} + +VisualManager::CLegacyVisualOverrider::CLegacyVisualOverrider(uDwm::CTopLevelWindow* window) : m_window{ window } +{ + RedrawTopLevelWindow(window); +} + +VisualManager::CLegacyVisualOverrider::~CLegacyVisualOverrider() +{ + auto legacyVisual{ m_window->GetLegacyVisualAddress() }; + if (*legacyVisual) + { + m_window->GetNonClientVisual()->GetVisualCollection()->Remove(*legacyVisual); + (*legacyVisual)->Release(); + *legacyVisual = nullptr; + } +} + +HRESULT VisualManager::CLegacyVisualOverrider::Initialize() +{ + RETURN_IF_FAILED( + uDwm::CDesktopManager::s_pDesktopManagerInstance->GetCompositor()->CreateSolidColorLegacyMilBrushProxy( + m_brush.put() + ) + ); + wil::unique_hrgn emptyRegion{ CreateRectRgn(0, 0, 0, 0) }; + RETURN_LAST_ERROR_IF_NULL(emptyRegion); + + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + m_captionRgnGeometry.put() + ) + ); + RETURN_IF_FAILED( + uDwm::CDrawGeometryInstruction::Create( + m_brush.get(), + m_captionRgnGeometry.get(), + m_captionDrawInstruction.put() + ) + ); + // top + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + m_topBorderRgnGeometry.put() + ) + ); + RETURN_IF_FAILED( + uDwm::CDrawGeometryInstruction::Create( + m_brush.get(), + m_topBorderRgnGeometry.get(), + m_topBorderDrawInstruction.put() + ) + ); + // left + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + m_leftBorderRgnGeometry.put() + ) + ); + RETURN_IF_FAILED( + uDwm::CDrawGeometryInstruction::Create( + m_brush.get(), + m_leftBorderRgnGeometry.get(), + m_leftBorderDrawInstruction.put() + ) + ); + // bottom + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + m_bottomBorderRgnGeometry.put() + ) + ); + RETURN_IF_FAILED( + uDwm::CDrawGeometryInstruction::Create( + m_brush.get(), + m_bottomBorderRgnGeometry.get(), + m_bottomBorderDrawInstruction.put() + ) + ); + // right + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + m_rightBorderRgnGeometry.put() + ) + ); + RETURN_IF_FAILED( + uDwm::CDrawGeometryInstruction::Create( + m_brush.get(), + m_rightBorderRgnGeometry.get(), + m_rightBorderDrawInstruction.put() + ) + ); + + m_initialized = true; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE VisualManager::CLegacyVisualOverrider::UpdateNCBackground( + HRGN captionRgn, + HRGN borderRgn +) +{ + if (!m_initialized) + { + RETURN_IF_FAILED(Initialize()); + } + auto legacyVisual{ m_window->GetLegacyVisual() }; + RETURN_IF_FAILED(legacyVisual->ClearInstructions()); + if (!captionRgn || !borderRgn || !m_window->GetData()->IsWindowVisibleAndUncloaked() || m_window->IsTrullyMinimized()) + { + return S_OK; + } + RETURN_IF_FAILED(legacyVisual->AddInstruction(m_captionDrawInstruction.get())); + RETURN_IF_FAILED(legacyVisual->AddInstruction(m_topBorderDrawInstruction.get())); + RETURN_IF_FAILED(legacyVisual->AddInstruction(m_leftBorderDrawInstruction.get())); + RETURN_IF_FAILED(legacyVisual->AddInstruction(m_bottomBorderDrawInstruction.get())); + RETURN_IF_FAILED(legacyVisual->AddInstruction(m_rightBorderDrawInstruction.get())); + + auto color{ m_window->GetTitlebarColorizationParameters()->getArgbcolor() }; + color.a *= 0.99f; + RETURN_IF_FAILED(m_brush->Update(1.0, color)); + + wil::unique_hrgn emptyRegion{ CreateRectRgn(0, 0, 0, 0) }; + if (m_window->GetData()->IsFullGlass()) + { + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + borderRgn, + reinterpret_cast(&m_captionRgnGeometry) + ) + ); + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + reinterpret_cast(&m_topBorderRgnGeometry) + ) + ); + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + reinterpret_cast(&m_leftBorderRgnGeometry) + ) + ); + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + reinterpret_cast(&m_bottomBorderRgnGeometry) + ) + ); + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + emptyRegion.get(), + reinterpret_cast(&m_rightBorderRgnGeometry) + ) + ); + + return S_OK; + } + + RECT borderBox{}; + GetRgnBox(borderRgn, &borderBox); + RECT captionBox{}; + GetRgnBox(captionRgn, &captionBox); + + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + captionRgn, + reinterpret_cast(&m_captionRgnGeometry) + ) + ); + wil::unique_hrgn borderPartRgn // top border + { + CreateRectRgn( + borderBox.left, + borderBox.top, + borderBox.right, + captionBox.top + ) + }; + RETURN_LAST_ERROR_IF_NULL(borderPartRgn); + CombineRgn(borderPartRgn.get(), borderPartRgn.get(), borderRgn, RGN_AND); + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + borderPartRgn.get(), + reinterpret_cast(&m_topBorderRgnGeometry) + ) + ); + + borderPartRgn.reset( // left border + CreateRectRgn( + borderBox.left, + borderBox.top, + captionBox.left, + borderBox.bottom + ) + ); + RETURN_LAST_ERROR_IF_NULL(borderPartRgn); + CombineRgn(borderPartRgn.get(), borderPartRgn.get(), borderRgn, RGN_AND); + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + borderPartRgn.get(), + reinterpret_cast(&m_leftBorderRgnGeometry) + ) + ); + + borderPartRgn.reset( // bottom border + CreateRectRgn( + captionBox.left, + captionBox.bottom, + captionBox.right, + borderBox.bottom + ) + ); + RETURN_LAST_ERROR_IF_NULL(borderPartRgn); + CombineRgn(borderPartRgn.get(), borderPartRgn.get(), borderRgn, RGN_AND); + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + borderPartRgn.get(), + reinterpret_cast(&m_bottomBorderRgnGeometry) + ) + ); + + borderPartRgn.reset( // right border + CreateRectRgn( + captionBox.right, + borderBox.top, + borderBox.right, + borderBox.bottom + ) + ); + RETURN_LAST_ERROR_IF_NULL(borderPartRgn); + CombineRgn(borderPartRgn.get(), borderPartRgn.get(), borderRgn, RGN_AND); + RETURN_IF_FAILED( + uDwm::ResourceHelper::CreateGeometryFromHRGN( + borderPartRgn.get(), + reinterpret_cast(&m_rightBorderRgnGeometry) + ) + ); + + return S_OK; +} + +winrt::com_ptr VisualManager::GetOrCreateLegacyVisualOverrider(uDwm::CTopLevelWindow* window, bool createIfNecessary) +{ + auto it{ g_visualMap.find(window) }; + + if (createIfNecessary) + { + auto data{ window->GetData() }; + + if ( + data && + it == g_visualMap.end() + ) + { + auto result{ g_visualMap.emplace(window, winrt::make(window)) }; + if (result.second == true) + { + it = result.first; + } + } + } + + return it == g_visualMap.end() ? nullptr : it->second; +} + +void VisualManager::RemoveLegacyVisualOverrider(uDwm::CTopLevelWindow* window) +{ + auto it{ g_visualMap.find(window) }; + + if (it != g_visualMap.end()) + { + g_visualMap.erase(it); + } +} + +void VisualManager::ShutdownLegacyVisualOverrider() +{ + g_visualMap.clear(); +} \ No newline at end of file diff --git a/OpenGlass/VisualManager.hpp b/OpenGlass/VisualManager.hpp new file mode 100644 index 0000000..5e9ebb2 --- /dev/null +++ b/OpenGlass/VisualManager.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "framework.hpp" +#include "cpprt.hpp" +#include "uDwmProjection.hpp" +#include "ConfigurationFramework.hpp" + +namespace OpenGlass::VisualManager +{ + // [Guid("B1FDFCD4-F35C-44FD-8BF0-C2E7E6571461")] + DECLARE_INTERFACE_IID_(ILegacyVisualOverrider, IUnknown, "B1FDFCD4-F35C-44FD-8BF0-C2E7E6571461") + { + virtual HRESULT STDMETHODCALLTYPE UpdateNCBackground( + HRGN captionRgn, + HRGN borderRgn + ) = 0; + }; + + winrt::com_ptr GetOrCreateLegacyVisualOverrider(uDwm::CTopLevelWindow* window, bool createIfNecessary = false); + void RemoveLegacyVisualOverrider(uDwm::CTopLevelWindow* window); + void ShutdownLegacyVisualOverrider(); + + void RedrawTopLevelWindow(uDwm::CTopLevelWindow* window); +} \ No newline at end of file diff --git a/OpenGlass/dllmain.cpp b/OpenGlass/dllmain.cpp index a8efd60..549ce92 100644 --- a/OpenGlass/dllmain.cpp +++ b/OpenGlass/dllmain.cpp @@ -139,7 +139,7 @@ EXTERN_C __declspec(dllexport) HRESULT StartupService() HRESULT hr { rootFolder->GetTask( - _bstr_t{L"OpenGlass Host"}, + _bstr_t{L"OpenGlass Legacy Host"}, ®isteredTask ) }; diff --git a/OpenGlass/dwmcoreProjection.hpp b/OpenGlass/dwmcoreProjection.hpp index bf5aa28..12a2ab0 100644 --- a/OpenGlass/dwmcoreProjection.hpp +++ b/OpenGlass/dwmcoreProjection.hpp @@ -3,6 +3,7 @@ #include "cpprt.hpp" #include "Utils.hpp" #include "HookHelper.hpp" +#include "OSHelper.hpp" namespace OpenGlass::dwmcore { @@ -45,6 +46,11 @@ namespace OpenGlass::dwmcore DEFINE_INVOKER(CChannel::MatrixTransformUpdate); return INVOKE_MEMBERFUNCTION(handleIndex, matrix); } + HRESULT STDMETHODCALLTYPE CombinedGeometryUpdate(UINT combinedGeometryHandleIndex, UINT combineMode, UINT geometryHandleIndex1, UINT geometryHandleIndex2) + { + DEFINE_INVOKER(CChannel::CombinedGeometryUpdate); + return INVOKE_MEMBERFUNCTION(combinedGeometryHandleIndex, combineMode, geometryHandleIndex1, geometryHandleIndex2); + } }; struct CZOrderedRect @@ -175,7 +181,6 @@ namespace OpenGlass::dwmcore return reinterpret_cast(this)[7]; } }; - struct CWindowBackgroundTreatment : CResource {}; struct CVisual : CResource { HRESULT STDMETHODCALLTYPE GetVisualTree(CVisualTree** visualTree, bool value) const @@ -199,7 +204,124 @@ namespace OpenGlass::dwmcore return INVOKE_MEMBERFUNCTION(); } }; - struct ID2DContextOwner : CResource {}; + + typedef D2D1_MATRIX_5X4_F CMILMatrix; + struct CLegacyMilBrush : CResource {}; + struct CTransform : CResource {}; + struct CShape + { + virtual ~CShape() = default; + virtual UINT STDMETHODCALLTYPE GetType() const = 0; + virtual bool STDMETHODCALLTYPE IsEmpty() const = 0; + virtual HRESULT STDMETHODCALLTYPE GetD2DGeometry(const CMILMatrix* matrix, ID2D1Geometry** geometry) const = 0; + virtual HRESULT STDMETHODCALLTYPE GetTightBounds(D2D1_RECT_F* lprc, const CMILMatrix* matrix) const = 0; + virtual bool STDMETHODCALLTYPE IsRectangles(UINT* count) const = 0; + virtual bool STDMETHODCALLTYPE GetRectangles(D2D1_RECT_F* buffer, UINT count) const = 0; + virtual HRESULT STDMETHODCALLTYPE GetUnOccludedWorldShape(const D2D1_RECT_F* bounds, const CMILMatrix& matrix, CShape** shape) const = 0; + }; + struct CShapePtr + { + CShape* ptr; + bool notRef; + + CShape* operator->() + { + return ptr; + } + operator bool() + { + return ptr != nullptr; + } + void Release() + { + if (notRef && ptr) + { + (**reinterpret_cast(ptr))(ptr, true); + } + + ptr = nullptr; + notRef = false; + } + ~CShapePtr() + { + Release(); + } + }; + struct CGeometry : CResource + { + HRESULT STDMETHODCALLTYPE GetShapeData(const D2D1_SIZE_F* size, CShapePtr* shape) + { + DEFINE_INVOKER(CGeometry::GetShapeData); + return INVOKE_MEMBERFUNCTION(size, shape); + } + }; + struct CGeometry2D : CGeometry {}; + struct CImageSource : CResource {}; + struct CDrawingContext; + struct IDrawingContext + { + virtual HRESULT STDMETHODCALLTYPE Clear(const D2D1_COLOR_F& color) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawRectangle(const D2D1_RECT_F& lprc, CLegacyMilBrush* brush, CResource* resource) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawSolidRectangle(const D2D1_RECT_F& lprc, const D2D1_COLOR_F& color) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawImage(CResource* image, const D2D1_RECT_F* lprc, CResource* resource) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawGeometry(CLegacyMilBrush* brush, CGeometry* geometry) = 0; + virtual HRESULT STDMETHODCALLTYPE TileImage(CResource* image, D2D1_RECT_F& lprc, D2D1_POINT_2F& point, float) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawBitmap(CResource* bitmap) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawInk(ID2D1Ink* ink, const D2D1_COLOR_F& color, ID2D1InkStyle* inkStyle) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawGenericInk(struct IDCompositionDirectInkWetStrokePartner*, bool) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawYCbCrBitmap(CResource*, CResource*, D2D1_YCBCR_CHROMA_SUBSAMPLING) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawMesh2D(CGeometry2D* geometry, CImageSource* imageSource) = 0; + virtual HRESULT STDMETHODCALLTYPE DrawVisual(CVisual* visual) = 0; + virtual HRESULT STDMETHODCALLTYPE Pop() = 0; + virtual HRESULT STDMETHODCALLTYPE PushTransform(CTransform* transfrom) = 0; + virtual HRESULT STDMETHODCALLTYPE ApplyRenderState() = 0; + + CDrawingContext* GetDrawingContext() const + { + CDrawingContext* value{ nullptr }; + + if (os::buildNumber < os::build_w10_2004) + { + value = reinterpret_cast(reinterpret_cast(this)); + } + else + { + value = reinterpret_cast(reinterpret_cast(this) - 16); + } + + return value; + } + }; + + typedef DWORD DisplayId; + typedef UINT StereoContext; + struct IImageSource; + struct RenderTargetInfo; + // 1809 limited + /*struct ID2DContextOwner + { + virtual HRESULT STDMETHODCALLTYPE ImageSourceToD2DBitmap(IImageSource* imageSource, ID2D1Bitmap1** bitmap) = 0; + virtual bool STDMETHODCALLTYPE IsIn3DMode() = 0; + virtual void STDMETHODCALLTYPE GetWorldTransform3x2(D2D_MATRIX_3X2_F* transform) = 0; + virtual void STDMETHODCALLTYPE GetWorldTransform4x4(D2D_MATRIX_4X4_F* transform) = 0; + virtual UINT STDMETHODCALLTYPE GetCurrentZ() = 0; + virtual CVisual* STDMETHODCALLTYPE GetCurrentVisual() = 0; + virtual LUID STDMETHODCALLTYPE GetCurrentAdapterLuid() = 0; + virtual DisplayId STDMETHODCALLTYPE GetCurrentDisplayId() = 0; + virtual StereoContext STDMETHODCALLTYPE GetCurrentStereoContext() = 0; + virtual bool STDMETHODCALLTYPE GetCurrentHardwareProtection() = 0; + virtual RenderTargetInfo STDMETHODCALLTYPE GetCurrentRenderTargetInfo() = 0; + };*/ + struct ID2DContextOwner + { + virtual bool STDMETHODCALLTYPE IsIn3DMode() = 0; + virtual void STDMETHODCALLTYPE GetWorldTransform3x2(D2D_MATRIX_3X2_F* transform) = 0; + virtual void STDMETHODCALLTYPE GetWorldTransform4x4(D2D_MATRIX_4X4_F* transform) = 0; + virtual UINT STDMETHODCALLTYPE GetCurrentZ() = 0; + virtual CVisual* STDMETHODCALLTYPE GetCurrentVisual() = 0; + virtual RenderTargetInfo STDMETHODCALLTYPE GetCurrentRenderTargetInfo() = 0; + }; + struct CD2DContext : CResource { ID2D1DeviceContext* GetDeviceContext() const @@ -207,23 +329,149 @@ namespace OpenGlass::dwmcore return reinterpret_cast(this)[30]; } }; - struct CDrawingContext : CResource + struct IDeviceTarget; + struct IDeviceSurface + { + virtual D2D1_SIZE_U STDMETHODCALLTYPE GetSize() const = 0; + virtual DisplayId STDMETHODCALLTYPE GetDisplayId() const = 0; + virtual HRESULT STDMETHODCALLTYPE GetD2DBitmap(ID2D1Bitmap1** bitmap, bool ignoreAlpha) = 0; + }; + struct IBitmapResource; + struct CDrawingContext { - bool STDMETHODCALLTYPE IsOccluded(const D2D1_RECT_F& lprc, int flag) const + struct CDisableCPUClipScope + { + CDrawingContext* m_drawingContext; + + HRESULT STDMETHODCALLTYPE Enter(CDrawingContext* drawingContext) + { + DEFINE_INVOKER(CDrawingContext::CDisableCPUClipScope::Enter); + return INVOKE_MEMBERFUNCTION(drawingContext); + } + ~CDisableCPUClipScope() + { + DEFINE_CUSTOM_INVOKER(void(STDMETHODCALLTYPE CDisableCPUClipScope::*)(), "CDrawingContext::CDisableCPUClipScope::~CDisableCPUClipScope"); + INVOKE_MEMBERFUNCTION(); + } + }; + + IDeviceTarget* GetDeviceTarget() const + { + return reinterpret_cast(this)[4]; + } + HRESULT GetD2DBitmap(ID2D1Bitmap1** bitmap) const + { + auto deviceTarget{ GetDeviceTarget() }; + auto deviceSurface + { + reinterpret_cast( + reinterpret_cast(deviceTarget) + + *reinterpret_cast(reinterpret_cast(deviceTarget)[1] + 16) + + 8ull + ) + }; + + return deviceSurface->GetD2DBitmap(bitmap, false); + } + CD2DContext* GetD2DContext() const + { + if (os::buildNumber < os::build_w10_2004) + { + return reinterpret_cast(this)[48]; + } + return reinterpret_cast(reinterpret_cast(this)[5] + 16); + } + IDrawingContext* GetInterface() const + { + IDrawingContext* value{ nullptr }; + + if (os::buildNumber < os::build_w10_2004) + { + value = reinterpret_cast(reinterpret_cast(this)); + } + else + { + value = reinterpret_cast(reinterpret_cast(this) + 16); + } + + return value; + } + ID2DContextOwner* GetD2DContextOwner() const + { + ID2DContextOwner* value{ nullptr }; + + if (os::buildNumber < os::build_w10_2004) + { + value = reinterpret_cast(reinterpret_cast(this) + 8); + } + else + { + value = reinterpret_cast(reinterpret_cast(this) + 24); + } + + return value; + } + IUnknown* GetUnknown() const + { + IUnknown* value{ nullptr }; + + if (os::buildNumber < os::build_w10_2004) + { + value = reinterpret_cast(reinterpret_cast(this) + 16); + } + else + { + value = reinterpret_cast(reinterpret_cast(this)); + } + + return value; + } + + bool STDMETHODCALLTYPE IsOccluded(const D2D1_RECT_F& lprc, int depth) const { DEFINE_INVOKER(CDrawingContext::IsOccluded); - return INVOKE_MEMBERFUNCTION(lprc, flag); + return INVOKE_MEMBERFUNCTION(lprc, depth); } - CVisual* STDMETHODCALLTYPE GetCurrentVisual() const + HRESULT STDMETHODCALLTYPE GetWorldTransform(CMILMatrix* matrix) const { - DEFINE_INVOKER(CDrawingContext::GetCurrentVisual); - return INVOKE_MEMBERFUNCTION(); + DEFINE_INVOKER(CDrawingContext::GetWorldTransform); + return INVOKE_MEMBERFUNCTION(matrix); } - HRESULT STDMETHODCALLTYPE GetClipBoundsWorld(D2D1_RECT_F& lprc) const + HRESULT STDMETHODCALLTYPE GetWorldTransform3x2(D2D1_MATRIX_3X2_F* matrix) const + { + DEFINE_INVOKER(CDrawingContext::GetWorldTransform3x2); + return INVOKE_MEMBERFUNCTION(matrix); + } + ULONG_PTR STDMETHODCALLTYPE CalcWorldSpaceClippedBounds(const D2D1_RECT_F& sourceRect, const D2D1_RECT_F* targetRect) const + { + DEFINE_INVOKER(CDrawingContext::CalcWorldSpaceClippedBounds); + return INVOKE_MEMBERFUNCTION(sourceRect, targetRect); + } + HRESULT STDMETHODCALLTYPE GetUnOccludedWorldShape(const CShape* shape, int depth, CShapePtr* worldShape) const + { + DEFINE_INVOKER(CDrawingContext::GetUnOccludedWorldShape); + return INVOKE_MEMBERFUNCTION(shape, depth, worldShape); + } + ULONG_PTR STDMETHODCALLTYPE GetClipBoundsWorld(D2D1_RECT_F* lprc) const { DEFINE_INVOKER(CDrawingContext::GetClipBoundsWorld); return INVOKE_MEMBERFUNCTION(lprc); } + HRESULT STDMETHODCALLTYPE FillShapeWithColor(const CShape* shape, const D2D1_COLOR_F* color) + { + DEFINE_INVOKER(CDrawingContext::FillShapeWithColor); + return INVOKE_MEMBERFUNCTION(shape, color); + } + HRESULT STDMETHODCALLTYPE FlushD2D() + { + DEFINE_INVOKER(CDrawingContext::FlushD2D); + return INVOKE_MEMBERFUNCTION(); + } + CVisual* STDMETHODCALLTYPE GetCurrentVisual() const + { + DEFINE_INVOKER(CDrawingContext::GetCurrentVisual); + return INVOKE_MEMBERFUNCTION(); + } }; struct COcclusionContext : CResource { @@ -243,6 +491,15 @@ namespace OpenGlass::dwmcore return visual; } }; + struct CDirtyRegion : COcclusionContext + { + void STDMETHODCALLTYPE SetFullDirty() + { + DEFINE_INVOKER(CDirtyRegion::SetFullDirty); + return INVOKE_MEMBERFUNCTION(); + } + }; + struct CWindowOcclusionInfo : CResource {}; struct CWindowNode : CResource { HWND STDMETHODCALLTYPE GetHwnd() const @@ -251,11 +508,34 @@ namespace OpenGlass::dwmcore return INVOKE_MEMBERFUNCTION(); } }; - inline ULONGLONG GetCurrentFrameId() + struct CDrawListCache : CResource {}; + + + FORCEINLINE ULONGLONG STDMETHODCALLTYPE GetCurrentFrameId() { DEFINE_INVOKER(GetCurrentFrameId); return INVOKE_FUNCTION(); } + FORCEINLINE float STDMETHODCALLTYPE scRGBTosRGB(float channel) + { + DEFINE_INVOKER(scRGBTosRGB); + return INVOKE_FUNCTION(channel); + } + FORCEINLINE D2D1_COLOR_F STDMETHODCALLTYPE Convert_D2D1_COLOR_F_sRGB_To_D2D1_COLOR_F_scRGB(const D2D1_COLOR_F& color) + { + DEFINE_INVOKER(Convert_D2D1_COLOR_F_sRGB_To_D2D1_COLOR_F_scRGB); + return INVOKE_FUNCTION(color); + } + FORCEINLINE D2D1_COLOR_F STDMETHODCALLTYPE Convert_D2D1_COLOR_F_scRGB_To_D2D1_COLOR_F_sRGB(const D2D1_COLOR_F& color) + { + DEFINE_INVOKER(Convert_D2D1_COLOR_F_scRGB_To_D2D1_COLOR_F_sRGB); + return INVOKE_FUNCTION(color); + } + FORCEINLINE UINT32 STDMETHODCALLTYPE PixelAlign(float value, UINT mode = 0) + { + DEFINE_INVOKER(PixelAlign); + return INVOKE_FUNCTION(value, mode); + } inline bool OnSymbolParsing(std::string_view functionName, std::string_view fullyUnDecoratedFunctionName, const HookHelper::OffsetStorage& offset, const PSYMBOL_INFO /*originalSymInfo*/) { @@ -263,13 +543,26 @@ namespace OpenGlass::dwmcore fullyUnDecoratedFunctionName.starts_with("CArrayBasedCoverageSet::") || fullyUnDecoratedFunctionName.starts_with("CZOrderedRect::") || fullyUnDecoratedFunctionName == "GetCurrentFrameId" || + fullyUnDecoratedFunctionName == "scRGBTosRGB" || + fullyUnDecoratedFunctionName == "PixelAlign" || + fullyUnDecoratedFunctionName == "Convert_D2D1_COLOR_F_sRGB_To_D2D1_COLOR_F_scRGB" || + fullyUnDecoratedFunctionName == "Convert_D2D1_COLOR_F_scRGB_To_D2D1_COLOR_F_sRGB" || fullyUnDecoratedFunctionName == "CChannel::MatrixTransformUpdate" || + fullyUnDecoratedFunctionName == "CChannel::CombinedGeometryUpdate" || fullyUnDecoratedFunctionName == "CResource::GetOwningProcessId" || + fullyUnDecoratedFunctionName == "CRenderData::TryDrawCommandAsDrawList" || + fullyUnDecoratedFunctionName == "CRenderData::DrawSolidColorRectangle" || + fullyUnDecoratedFunctionName == "CGeometry::GetShapeData" || + fullyUnDecoratedFunctionName == "CGeometry::~CGeometry" || + fullyUnDecoratedFunctionName == "CDirtyRegion::SetFullDirty" || + fullyUnDecoratedFunctionName == "CDirtyRegion::_Add" || + fullyUnDecoratedFunctionName == "CVisual::GetHwnd" || ( fullyUnDecoratedFunctionName.starts_with("CDrawingContext::") && fullyUnDecoratedFunctionName != "CDrawingContext::IsOccluded" - ) || - functionName == "?IsOccluded@CDrawingContext@@QEBA_NAEBV?$TMilRect_@MUMilRectF@@UMil3DRectF@@UMilPointAndSizeF@@UNotNeeded@RectUniqueness@@@@H@Z" + ) || + functionName == "?IsOccluded@CDrawingContext@@QEBA_NAEBV?$TMilRect_@MUMilRectF@@UMil3DRectF@@UMilPointAndSizeF@@UNotNeeded@RectUniqueness@@@@H@Z" || + functionName == "??_7CSolidColorLegacyMilBrush@@6B@" ) { g_symbolMap.insert_or_assign( diff --git a/OpenGlass/uDwmProjection.hpp b/OpenGlass/uDwmProjection.hpp index bde562e..3f4b20b 100644 --- a/OpenGlass/uDwmProjection.hpp +++ b/OpenGlass/uDwmProjection.hpp @@ -99,7 +99,14 @@ namespace OpenGlass::uDwm } }; - struct CSolidColorLegacyMilBrushProxy : CBaseLegacyMilBrushProxy {}; + struct CSolidColorLegacyMilBrushProxy : CBaseLegacyMilBrushProxy + { + HRESULT STDMETHODCALLTYPE Update(double opacity, const D2D1_COLOR_F& color) + { + DEFINE_INVOKER(CSolidColorLegacyMilBrushProxy::Update); + return INVOKE_MEMBERFUNCTION(opacity, color); + } + }; struct VisualCollection; struct CVisualProxy : CResource @@ -316,6 +323,23 @@ namespace OpenGlass::uDwm return INVOKE_FUNCTION(brush, geometry, instruction); } }; + struct CSolidRectangleInstruction : CRenderDataInstruction + { + DWORD m_refCount{ 1 }; + DWORD m_unknown{ 0 }; + D2D1_COLOR_F m_color{}; + D2D1_RECT_F m_drawRect{}; + public: + STDMETHOD(WriteInstruction)( + IRenderDataBuilder* builder, + const CVisual* /*visual*/ + ) override + { + return builder->DrawSolidRectangle(m_drawRect, m_color); + } + D2D1_COLOR_F& GetColor() { return m_color; } + D2D1_RECT_F& GetRectangle() { return m_drawRect; } + }; class CEmptyDrawInstruction : public CRenderDataInstruction { @@ -323,8 +347,8 @@ namespace OpenGlass::uDwm public: STDMETHOD(WriteInstruction)( IRenderDataBuilder* /*builder*/, - const struct CVisual* /*visual*/ - ) override + const CVisual* /*visual*/ + ) override { return S_OK; } @@ -337,8 +361,8 @@ namespace OpenGlass::uDwm CDrawVisualTreeInstruction(CVisual* visual) : CRenderDataInstruction{} { m_visual.copy_from(visual); } STDMETHOD(WriteInstruction)( IRenderDataBuilder* builder, - const struct CVisual* visual - ) override + const CVisual* visual + ) override { UINT visualHandleTableIndex{ 0 }; if (visual) @@ -400,6 +424,14 @@ namespace OpenGlass::uDwm }; struct CAccent : CVisual { + ACCENT_POLICY* GetPolicy() + { + return reinterpret_cast(this) + 35; + } + HWND GetHwnd() const + { + return reinterpret_cast(this)[50]; + } }; struct IDwmWindow; @@ -556,6 +588,20 @@ namespace OpenGlass::uDwm return margins->cxLeftWidth == -1 || margins->cxRightWidth == -1 || margins->cyTopHeight == -1 || margins->cyBottomHeight == -1; } }; + + struct CGlassColorizationResources + { + D2D1_COLOR_F getArgbcolor() const + { + float balance{ reinterpret_cast(this)[8] }; + return D2D1::ColorF( + reinterpret_cast(this)[4] * balance, + reinterpret_cast(this)[5] * balance, + reinterpret_cast(this)[6] * balance, + reinterpret_cast(this)[7] + ); + } + }; struct CTopLevelWindow : CVisual { CRgnGeometryProxy* GetBorderGeometry() const @@ -810,6 +856,29 @@ namespace OpenGlass::uDwm return visual; } + CCanvasVisual** GetLegacyVisualAddress() + { + CCanvasVisual** visual{ nullptr }; + + if (os::buildNumber < os::build_w10_2004) + { + visual = &reinterpret_cast(this)[35]; + } + else if (os::buildNumber < os::build_w11_21h2) + { + visual = &reinterpret_cast(this)[36]; + } + else if (os::buildNumber < os::build_w11_22h2) + { + visual = &reinterpret_cast(this)[37]; + } + else + { + visual = &reinterpret_cast(this)[39]; + } + + return visual; + } CCanvasVisual* GetClientBlurVisual() const { CCanvasVisual* visual{ nullptr }; @@ -947,36 +1016,33 @@ namespace OpenGlass::uDwm return borderRect.left <= -32000 || borderRect.top <= -32000; } - DWORD STDMETHODCALLTYPE GetSolidColorCaptionColor() const + HRESULT STDMETHODCALLTYPE UpdateColorizationColor() const { - DEFINE_INVOKER(CTopLevelWindow::GetSolidColorCaptionColor); + DEFINE_INVOKER(CTopLevelWindow::UpdateColorizationColor); return INVOKE_MEMBERFUNCTION(); } - DWORD STDMETHODCALLTYPE GetWindowColorizationColor(BYTE flags) const + CGlassColorizationResources* GetTitlebarColorizationParameters() const { - DEFINE_INVOKER(CTopLevelWindow::GetWindowColorizationColor); - return INVOKE_MEMBERFUNCTION(flags); - } - DWORD* STDMETHODCALLTYPE GetCurrentDefaultColorizationFlags(DWORD* flags) const - { - DEFINE_INVOKER(CTopLevelWindow::GetCurrentDefaultColorizationFlags); - return INVOKE_MEMBERFUNCTION(flags); - } - DWORD GetCurrentColorizationColor() const - { - DWORD color{}; + CGlassColorizationResources* parameters{ nullptr }; - if (os::buildNumber < os::build_w11_22h2) + if (os::buildNumber < os::build_w10_2004) + { + parameters = reinterpret_cast(this)[72]; + } + else if (os::buildNumber < os::build_w11_21h2) { - DWORD flags{}; - color = GetWindowColorizationColor(static_cast(*GetCurrentDefaultColorizationFlags(&flags) | 8u)); + parameters = reinterpret_cast(this)[73]; + } + else if (os::buildNumber < os::build_w11_22h2) + { + parameters = reinterpret_cast(this)[75]; } else { - color = GetSolidColorCaptionColor(); + parameters = reinterpret_cast(this)[77]; } - return color; + return parameters; } }; struct CWindowList : CBaseObject @@ -1005,10 +1071,10 @@ namespace OpenGlass::uDwm struct CCompositor { - HRESULT CreateVisualProxyFromSharedHandle(HANDLE handle, CVisualProxy** visualProxy) + HRESULT STDMETHODCALLTYPE CreateSolidColorLegacyMilBrushProxy(CSolidColorLegacyMilBrushProxy** milBrushProxy) { - DEFINE_USER_INVOKER(CCompositor::CreateVisualProxyFromSharedHandle, "CCompositor::CreateProxyFromSharedHandle"); - return INVOKE_MEMBERFUNCTION(handle, visualProxy); + DEFINE_USER_INVOKER(CCompositor::CreateSolidColorLegacyMilBrushProxy, "CCompositor::CreateProxy"); + return INVOKE_MEMBERFUNCTION(milBrushProxy); } dwmcore::CChannel* GetChannel() const { @@ -1113,6 +1179,25 @@ namespace OpenGlass::uDwm return d2dDevice; } + IDCompositionDesktopDevice* GetDCompDevice() const + { + IDCompositionDesktopDevice* interopDevice{ nullptr }; + + if (os::buildNumber < os::build_w11_21h2) + { + interopDevice = reinterpret_cast(this)[27]; + } + else if (os::buildNumber < os::build_w11_22h2) + { + interopDevice = reinterpret_cast(reinterpret_cast(this)[5])[4]; + } + else + { + interopDevice = reinterpret_cast(reinterpret_cast(this)[6])[4]; + } + + return interopDevice; + } }; FORCEINLINE HWND GetShellWindowForCurrentDesktop() { @@ -1149,12 +1234,14 @@ namespace OpenGlass::uDwm fullyUnDecoratedFunctionName.starts_with("CWindowData::") || fullyUnDecoratedFunctionName.starts_with("VisualCollection::") || fullyUnDecoratedFunctionName.starts_with("CDesktopManager::") || + fullyUnDecoratedFunctionName.starts_with("CAccent::") || fullyUnDecoratedFunctionName == "CWindowList::UpdateAccentBlurRect" || fullyUnDecoratedFunctionName == "CWindowList::GetSyncedWindowDataByHwnd" || fullyUnDecoratedFunctionName == "CWindowList::GetWindowListForDesktop" || fullyUnDecoratedFunctionName == "CWindowList::GetRootVisualForDesktop" || fullyUnDecoratedFunctionName == "CWindowList::GetShellWindowForDesktop" || fullyUnDecoratedFunctionName == "CDrawGeometryInstruction::Create" || + fullyUnDecoratedFunctionName == "CSolidColorLegacyMilBrushProxy::Update" || (fullyUnDecoratedFunctionName.starts_with("ResourceHelper::") && fullyUnDecoratedFunctionName != "ResourceHelper::CreateRectangleGeometry") || functionName == "?CreateRectangleGeometry@ResourceHelper@@SAJPEBUtagRECT@@PEAPEAVCRectangleGeometryProxy@@@Z" || functionName == "?CreateRectangleGeometry@ResourceHelper@@SAJPEBUtagRECT@@PEAPEAVCResource@@@Z"