From 92a3ff9b2a9afdd67c3a18e25596d815940f3891 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Wed, 14 Oct 2020 14:45:50 +0200 Subject: [PATCH 01/22] Started work --- src/modules/fancyzones/lib/ZoneWindow.cpp | 4 ++-- src/modules/fancyzones/lib/ZoneWindowDrawing.cpp | 2 +- src/modules/fancyzones/lib/ZoneWindowDrawing.h | 14 +++++++++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 09499186f..689735dec 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -87,11 +87,11 @@ namespace ZoneWindowUtils HPAINTBUFFER bufferedPaint = BeginBufferedPaint(hdc, &clientRect, BPBF_TOPDOWNDIB, nullptr, &hdcMem); if (bufferedPaint) { - ZoneWindowDrawing::DrawBackdrop(hdcMem, clientRect); + ZoneWindowDrawingNS::DrawBackdrop(hdcMem, clientRect); if (hasActiveZoneSet) { - ZoneWindowDrawing::DrawActiveZoneSet(hdcMem, + ZoneWindowDrawingNS::DrawActiveZoneSet(hdcMem, hostZoneColor, hostZoneBorderColor, hostZoneHighlightColor, diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index e47951eab..d18dc2868 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -103,7 +103,7 @@ namespace } } -namespace ZoneWindowDrawing +namespace ZoneWindowDrawingNS { void DrawBackdrop(wil::unique_hdc& hdc, RECT const& clientRect) noexcept { diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index 35932a57b..62aed1873 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -4,12 +4,13 @@ #include #include #include +#include #include "util.h" #include "Zone.h" #include "ZoneSet.h" -namespace ZoneWindowDrawing +namespace ZoneWindowDrawingNS { struct ColorSetting { @@ -30,3 +31,14 @@ namespace ZoneWindowDrawing const std::vector& highlightZones, bool flashMode) noexcept; } + +class ZoneWindowDrawing +{ + HWND m_window; + winrt::com_ptr m_host; + +public: + ZoneWindowDrawing(HWND window); + void StartAnimation(unsigned millis); + void DrawActiveZoneSet(const std::vector>& zones, const std::vector& highlightZones); +}; \ No newline at end of file From 0c544409dd33c004e30d44ebae939e370b417c22 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 20 Oct 2020 15:19:10 +0200 Subject: [PATCH 02/22] Good progress on D2D --- src/modules/fancyzones/lib/ZoneWindow.cpp | 13 +- .../fancyzones/lib/ZoneWindowDrawing.h | 171 +++++++++++++++++- 2 files changed, 177 insertions(+), 7 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 689735dec..cf6efe5d7 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -158,6 +158,7 @@ private: void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept; LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; void OnPaint(HDC hdc) noexcept; + void OnPaintD2D() noexcept; void OnKeyUp(WPARAM wparam) noexcept; std::vector ZonesFromPoint(POINT pt) noexcept; void CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept; @@ -181,6 +182,7 @@ private: std::atomic m_animating; OnThreadExecutor m_paintExecutor; ULONG_PTR gdiplusToken; + std::unique_ptr m_zoneWindowDrawing; }; ZoneWindow::ZoneWindow(HINSTANCE hinstance) @@ -240,6 +242,7 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit MakeWindowTransparent(m_window.get()); + m_zoneWindowDrawing = std::make_unique(m_window.get()); // Ignore flashZones /* if (flashZones) @@ -596,12 +599,12 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept case WM_PRINTCLIENT: { - OnPaint(reinterpret_cast(wparam)); + // OnPaint(reinterpret_cast(wparam)); } break; case WM_PAINT: { - OnPaint(NULL); + OnPaintD2D(); } break; @@ -659,6 +662,12 @@ void ZoneWindow::OnPaint(HDC hdc) noexcept } } +void ZoneWindow::OnPaintD2D() noexcept +{ + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); + m_zoneWindowDrawing->Render(); +} + void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept { bool fRedraw = false; diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index 62aed1873..e3d837f5e 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -34,11 +34,172 @@ namespace ZoneWindowDrawingNS class ZoneWindowDrawing { + struct DrawableRect + { + D2D1_RECT_F rect; + D2D1_COLOR_F borderColor; + D2D1_COLOR_F fillColor; + }; + HWND m_window; - winrt::com_ptr m_host; + RECT m_clientRect; + // winrt::com_ptr m_host; + ID2D1HwndRenderTarget* m_renderTarget; + + std::mutex m_sceneMutex; + std::vector m_sceneRects; + std::vector m_sceneLabels; + + void DrawBackdrop() + { + m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); + } + + static ID2D1Factory* GetD2DFactory() + { + static ID2D1Factory* pD2DFactory = 0; + if (!pD2DFactory) + { + D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &pD2DFactory); + } + return pD2DFactory; + + // TODO: Destroy factory + } + + static D2D1_COLOR_F ConvertColor(COLORREF color) + { + return D2D1::ColorF(GetRValue(color) / 255.f, + GetGValue(color) / 255.f, + GetBValue(color) / 255.f, + 1.f); + } + + static D2D1_RECT_F ConvertRect(RECT rect) + { + return D2D1::RectF(rect.left, rect.top, rect.right, rect.bottom); + } public: - ZoneWindowDrawing(HWND window); - void StartAnimation(unsigned millis); - void DrawActiveZoneSet(const std::vector>& zones, const std::vector& highlightZones); -}; \ No newline at end of file + ZoneWindowDrawing(HWND window) + { + m_window = window; + + // Obtain the size of the drawing area. + GetClientRect(window, &m_clientRect); + + // Create a Direct2D render target + GetD2DFactory()->CreateHwndRenderTarget( + D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)), + D2D1::HwndRenderTargetProperties( + window, + D2D1::SizeU( + m_clientRect.right - m_clientRect.left, + m_clientRect.bottom - m_clientRect.top)), + &m_renderTarget); + } + + void Render() + { + std::unique_lock lock(m_sceneMutex); + + m_renderTarget->BeginDraw(); + DrawBackdrop(); + + for (const auto& drawableRect : m_sceneRects) + { + ID2D1SolidColorBrush* borderBrush = NULL; + ID2D1SolidColorBrush* fillBrush = NULL; + // TODO: hresult and null checks + m_renderTarget->CreateSolidColorBrush(drawableRect.borderColor, &borderBrush); + m_renderTarget->CreateSolidColorBrush(drawableRect.fillColor, &fillBrush); + + if (fillBrush) + { + m_renderTarget->FillRectangle(drawableRect.rect, fillBrush); + fillBrush->Release(); + } + + if (borderBrush) + { + m_renderTarget->DrawRectangle(drawableRect.rect, borderBrush); + borderBrush->Release(); + } + } + + m_renderTarget->EndDraw(); + } + + void StartAnimation(unsigned millis) + { + + } + + void DrawActiveZoneSet(const std::vector>& zones, + const std::vector& highlightZones, + winrt::com_ptr host) + { + std::unique_lock lock(m_sceneMutex); + + m_sceneRects = {}; + + auto borderColor = ConvertColor(host->GetZoneBorderColor()); + auto inactiveColor = ConvertColor(host->GetZoneColor()); + auto highlightColor = ConvertColor(host->GetZoneHighlightColor()); + + inactiveColor.a = host->GetZoneHighlightOpacity() / 255.f; + highlightColor.a = host->GetZoneHighlightOpacity() / 255.f; + + std::vector isHighlighted(zones.size(), false); + for (size_t x : highlightZones) + { + isHighlighted[x] = true; + } + + // First draw the inactive zones + for (auto iter = zones.begin(); iter != zones.end(); iter++) + { + int zoneId = static_cast(iter - zones.begin()); + winrt::com_ptr zone = iter->try_as(); + if (!zone) + { + continue; + } + + if (!isHighlighted[zoneId]) + { + DrawableRect drawableRect{ + .rect = ConvertRect(zone->GetZoneRect()), + .borderColor = borderColor, + .fillColor = inactiveColor + }; + + m_sceneRects.push_back(drawableRect); + } + } + + // Draw the active zones on top of the inactive zones + for (auto iter = zones.begin(); iter != zones.end(); iter++) + { + int zoneId = static_cast(iter - zones.begin()); + winrt::com_ptr zone = iter->try_as(); + if (!zone) + { + continue; + } + + if (isHighlighted[zoneId]) + { + DrawableRect drawableRect{ + .rect = ConvertRect(zone->GetZoneRect()), + .borderColor = borderColor, + .fillColor = highlightColor + }; + + m_sceneRects.push_back(drawableRect); + } + } + } +}; From a022b2231f0a8cc07fc5e55b85a95c243fd0f939 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 20 Oct 2020 15:49:05 +0200 Subject: [PATCH 03/22] Visuals are good, functionality - almost there --- .../fancyzones/lib/ZoneWindowDrawing.h | 71 ++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index e3d837f5e..c2eb99fca 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "util.h" #include "Zone.h" @@ -39,6 +40,7 @@ class ZoneWindowDrawing D2D1_RECT_F rect; D2D1_COLOR_F borderColor; D2D1_COLOR_F fillColor; + size_t id; }; HWND m_window; @@ -48,7 +50,6 @@ class ZoneWindowDrawing std::mutex m_sceneMutex; std::vector m_sceneRects; - std::vector m_sceneLabels; void DrawBackdrop() { @@ -57,7 +58,7 @@ class ZoneWindowDrawing static ID2D1Factory* GetD2DFactory() { - static ID2D1Factory* pD2DFactory = 0; + static ID2D1Factory* pD2DFactory = nullptr; if (!pD2DFactory) { D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &pD2DFactory); @@ -67,6 +68,18 @@ class ZoneWindowDrawing // TODO: Destroy factory } + static IDWriteFactory* GetWriteFactory() + { + static IUnknown* pDWriteFactory = nullptr; + if (!pDWriteFactory) + { + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &pDWriteFactory); + } + return reinterpret_cast(pDWriteFactory); + + // TODO: Destroy factory + } + static D2D1_COLOR_F ConvertColor(COLORREF color) { return D2D1::ColorF(GetRValue(color) / 255.f, @@ -84,9 +97,13 @@ public: ZoneWindowDrawing(HWND window) { m_window = window; + m_renderTarget = nullptr; // Obtain the size of the drawing area. - GetClientRect(window, &m_clientRect); + if (!GetClientRect(window, &m_clientRect)) + { + return; + } // Create a Direct2D render target GetD2DFactory()->CreateHwndRenderTarget( @@ -105,16 +122,24 @@ public: { std::unique_lock lock(m_sceneMutex); + if (!m_renderTarget) + { + return; + } + m_renderTarget->BeginDraw(); DrawBackdrop(); + + for (const auto& drawableRect : m_sceneRects) { - ID2D1SolidColorBrush* borderBrush = NULL; - ID2D1SolidColorBrush* fillBrush = NULL; - // TODO: hresult and null checks + ID2D1SolidColorBrush* borderBrush = nullptr; + ID2D1SolidColorBrush* fillBrush = nullptr; + ID2D1SolidColorBrush* textBrush = nullptr; m_renderTarget->CreateSolidColorBrush(drawableRect.borderColor, &borderBrush); m_renderTarget->CreateSolidColorBrush(drawableRect.fillColor, &fillBrush); + m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &textBrush); if (fillBrush) { @@ -127,6 +152,34 @@ public: m_renderTarget->DrawRectangle(drawableRect.rect, borderBrush); borderBrush->Release(); } + + std::wstring idStr = std::to_wstring(drawableRect.id); + + // TODO: mark string as non-localizable + IDWriteTextFormat* textFormat = nullptr; + auto writeFactory = GetWriteFactory(); + + if (writeFactory) + { + writeFactory->CreateTextFormat(L"Segoe ui", nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 80.f, L"en-US", &textFormat); + } + + if (textFormat && textBrush) + { + textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); + textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + m_renderTarget->DrawTextW(idStr.c_str(), idStr.size(), textFormat, drawableRect.rect, textBrush); + } + + if (textFormat) + { + textFormat->Release(); + } + + if (textBrush) + { + textBrush->Release(); + } } m_renderTarget->EndDraw(); @@ -173,7 +226,8 @@ public: DrawableRect drawableRect{ .rect = ConvertRect(zone->GetZoneRect()), .borderColor = borderColor, - .fillColor = inactiveColor + .fillColor = inactiveColor, + .id = zone->Id() }; m_sceneRects.push_back(drawableRect); @@ -195,7 +249,8 @@ public: DrawableRect drawableRect{ .rect = ConvertRect(zone->GetZoneRect()), .borderColor = borderColor, - .fillColor = highlightColor + .fillColor = highlightColor, + .id = zone->Id() }; m_sceneRects.push_back(drawableRect); From f637cd32029891049349f73516c23daedaee5152 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 20 Oct 2020 15:51:50 +0200 Subject: [PATCH 04/22] Opacity fix --- src/modules/fancyzones/lib/ZoneWindowDrawing.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index c2eb99fca..4c1f927f8 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -202,8 +202,8 @@ public: auto inactiveColor = ConvertColor(host->GetZoneColor()); auto highlightColor = ConvertColor(host->GetZoneHighlightColor()); - inactiveColor.a = host->GetZoneHighlightOpacity() / 255.f; - highlightColor.a = host->GetZoneHighlightOpacity() / 255.f; + inactiveColor.a = host->GetZoneHighlightOpacity() / 100.f; + highlightColor.a = host->GetZoneHighlightOpacity() / 100.f; std::vector isHighlighted(zones.size(), false); for (size_t x : highlightZones) From 92e8a84a4e7b158c77e7583f7ca577d4bdc8b8da Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Thu, 22 Oct 2020 15:43:20 +0200 Subject: [PATCH 05/22] Animation works, WM_PAINT still doesn't --- src/modules/fancyzones/lib/ZoneWindow.cpp | 17 +---- .../fancyzones/lib/ZoneWindowDrawing.h | 66 +++++++++++++++---- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index cf6efe5d7..55aa6aef0 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -179,7 +179,7 @@ private: static const UINT m_showAnimationDuration = 200; // ms static const UINT m_flashDuration = 700; // ms - std::atomic m_animating; + std::atomic m_animating; // TODO remove OnThreadExecutor m_paintExecutor; ULONG_PTR gdiplusToken; std::unique_ptr m_zoneWindowDrawing; @@ -454,18 +454,7 @@ ZoneWindow::ShowZoneWindow() noexcept } SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags); - - std::thread{ [this, strong_this{ get_strong() }]() { - m_animating = true; - auto window = m_window.get(); - AnimateWindow(window, m_showAnimationDuration, AW_BLEND); - InvalidateRect(window, nullptr, true); - if (!m_host->InMoveSize()) - { - HideZoneWindow(); - } - m_animating = false; - } }.detach(); + m_zoneWindowDrawing->Show(m_showAnimationDuration); } IFACEMETHODIMP_(void) @@ -473,7 +462,7 @@ ZoneWindow::HideZoneWindow() noexcept { if (m_window) { - ShowWindow(m_window.get(), SW_HIDE); + m_zoneWindowDrawing->Hide(); m_keyLast = 0; m_windowMoveSize = nullptr; m_highlightZone = {}; diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index 4c1f927f8..693e23df2 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -47,15 +47,38 @@ class ZoneWindowDrawing RECT m_clientRect; // winrt::com_ptr m_host; ID2D1HwndRenderTarget* m_renderTarget; + std::optional m_tAnimationStart; + unsigned m_animationDuration; - std::mutex m_sceneMutex; + std::mutex m_mutex; std::vector m_sceneRects; void DrawBackdrop() { + // Lock is being held m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); } + float GetAnimationAlpha() + { + // Lock is being held + if (!m_tAnimationStart) + { + return 1.f; + } + + auto tNow = std::chrono::steady_clock().now(); + auto alpha = (tNow - *m_tAnimationStart).count() / (1e6f * m_animationDuration); + if (alpha < 1.f) + { + return alpha; + } + else + { + return 1.f; + } + } + static ID2D1Factory* GetD2DFactory() { static ID2D1Factory* pD2DFactory = nullptr; @@ -90,7 +113,7 @@ class ZoneWindowDrawing static D2D1_RECT_F ConvertRect(RECT rect) { - return D2D1::RectF(rect.left, rect.top, rect.right, rect.bottom); + return D2D1::RectF((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom); } public: @@ -98,6 +121,7 @@ public: { m_window = window; m_renderTarget = nullptr; + m_animationDuration = 0; // Obtain the size of the drawing area. if (!GetClientRect(window, &m_clientRect)) @@ -120,7 +144,7 @@ public: void Render() { - std::unique_lock lock(m_sceneMutex); + std::unique_lock lock(m_mutex); if (!m_renderTarget) { @@ -129,17 +153,21 @@ public: m_renderTarget->BeginDraw(); DrawBackdrop(); - - - - for (const auto& drawableRect : m_sceneRects) + float animationAlpha = GetAnimationAlpha(); + + for (auto drawableRect : m_sceneRects) { ID2D1SolidColorBrush* borderBrush = nullptr; ID2D1SolidColorBrush* fillBrush = nullptr; ID2D1SolidColorBrush* textBrush = nullptr; + + // Need to copy the rect from m_sceneRects + drawableRect.borderColor.a *= animationAlpha; + drawableRect.fillColor.a *= animationAlpha; + m_renderTarget->CreateSolidColorBrush(drawableRect.borderColor, &borderBrush); m_renderTarget->CreateSolidColorBrush(drawableRect.fillColor, &fillBrush); - m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &textBrush); + m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, animationAlpha), &textBrush); if (fillBrush) { @@ -168,7 +196,7 @@ public: { textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); - m_renderTarget->DrawTextW(idStr.c_str(), idStr.size(), textFormat, drawableRect.rect, textBrush); + m_renderTarget->DrawTextW(idStr.c_str(), (UINT32)idStr.size(), textFormat, drawableRect.rect, textBrush); } if (textFormat) @@ -185,16 +213,32 @@ public: m_renderTarget->EndDraw(); } - void StartAnimation(unsigned millis) + void Hide() { + std::unique_lock lock(m_mutex); + if (m_tAnimationStart) + { + m_tAnimationStart.reset(); + ShowWindow(m_window, SW_HIDE); + } + } + void Show(unsigned animationMillis) + { + std::unique_lock lock(m_mutex); + if (!m_tAnimationStart) + { + ShowWindow(m_window, SW_SHOWDEFAULT); + m_tAnimationStart = std::chrono::steady_clock().now(); + m_animationDuration = animationMillis; + } } void DrawActiveZoneSet(const std::vector>& zones, const std::vector& highlightZones, winrt::com_ptr host) { - std::unique_lock lock(m_sceneMutex); + std::unique_lock lock(m_mutex); m_sceneRects = {}; From f7d3c2064840843ed810a7bf8a71296fdf108500 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Thu, 22 Oct 2020 23:27:55 +0200 Subject: [PATCH 06/22] Simplify code, remove flashZones, remove unused code --- src/modules/fancyzones/lib/FancyZones.cpp | 6 +- src/modules/fancyzones/lib/ZoneWindow.cpp | 162 +----------------- src/modules/fancyzones/lib/ZoneWindow.h | 2 +- .../fancyzones/lib/ZoneWindowDrawing.cpp | 153 ----------------- .../tests/UnitTests/ZoneWindow.Spec.cpp | 72 ++++---- 5 files changed, 42 insertions(+), 353 deletions(-) diff --git a/src/modules/fancyzones/lib/FancyZones.cpp b/src/modules/fancyzones/lib/FancyZones.cpp index 1d8cb6c7e..770d61dbb 100644 --- a/src/modules/fancyzones/lib/FancyZones.cpp +++ b/src/modules/fancyzones/lib/FancyZones.cpp @@ -937,17 +937,13 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, const std::wstring& deviceId) n uniqueId = ZoneWindowUtils::GenerateUniqueIdAllMonitorsArea(virtualDesktopId.get()); } - // "Turning FLASHING_ZONE option off" - //const bool flash = m_settings->GetSettings()->zoneSetChange_flashZones; - const bool flash = false; - std::wstring parentId{}; auto parentArea = m_workAreaHandler.GetWorkArea(m_previousDesktopId, monitor); if (parentArea) { parentId = parentArea->UniqueId(); } - auto workArea = MakeZoneWindow(this, m_hinstance, monitor, uniqueId, parentId, flash); + auto workArea = MakeZoneWindow(this, m_hinstance, monitor, uniqueId, parentId); if (workArea) { m_workAreaHandler.AddWorkArea(m_currentDesktopId, monitor, workArea); diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 55aa6aef0..b2a74ab34 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -61,54 +61,6 @@ namespace ZoneWindowUtils return result; } - - void PaintZoneWindow(HDC hdc, - HWND window, - bool hasActiveZoneSet, - COLORREF hostZoneColor, - COLORREF hostZoneBorderColor, - COLORREF hostZoneHighlightColor, - int hostZoneHighlightOpacity, - IZoneSet::ZonesMap zones, - std::vector highlightZone, - bool flashMode) - { - PAINTSTRUCT ps; - HDC oldHdc = hdc; - if (!hdc) - { - hdc = BeginPaint(window, &ps); - } - - RECT clientRect; - GetClientRect(window, &clientRect); - - wil::unique_hdc hdcMem; - HPAINTBUFFER bufferedPaint = BeginBufferedPaint(hdc, &clientRect, BPBF_TOPDOWNDIB, nullptr, &hdcMem); - if (bufferedPaint) - { - ZoneWindowDrawingNS::DrawBackdrop(hdcMem, clientRect); - - if (hasActiveZoneSet) - { - ZoneWindowDrawingNS::DrawActiveZoneSet(hdcMem, - hostZoneColor, - hostZoneBorderColor, - hostZoneHighlightColor, - hostZoneHighlightOpacity, - zones, - highlightZone, - flashMode); - } - - EndBufferedPaint(bufferedPaint, TRUE); - } - - if (!oldHdc) - { - EndPaint(window, &ps); - } - } } struct ZoneWindow : public winrt::implements @@ -117,7 +69,7 @@ public: ZoneWindow(HINSTANCE hinstance); ~ZoneWindow(); - bool Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, bool flashZones); + bool Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId); IFACEMETHODIMP MoveSizeEnter(HWND window) noexcept; IFACEMETHODIMP MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled, bool selectManyZones) noexcept; @@ -162,14 +114,12 @@ private: void OnKeyUp(WPARAM wparam) noexcept; std::vector ZonesFromPoint(POINT pt) noexcept; void CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept; - void FlashZones() noexcept; winrt::com_ptr m_host; HMONITOR m_monitor{}; std::wstring m_uniqueId; // Parsed deviceId + resolution + virtualDesktopId wil::unique_hwnd m_window{}; // Hidden tool window used to represent current monitor desktop work area. HWND m_windowMoveSize{}; - bool m_flashMode{}; winrt::com_ptr m_activeZoneSet; std::vector> m_zoneSets; std::vector m_initialHighlightZone; @@ -178,10 +128,6 @@ private: size_t m_keyCycle{}; static const UINT m_showAnimationDuration = 200; // ms static const UINT m_flashDuration = 700; // ms - - std::atomic m_animating; // TODO remove - OnThreadExecutor m_paintExecutor; - ULONG_PTR gdiplusToken; std::unique_ptr m_zoneWindowDrawing; }; @@ -194,19 +140,13 @@ ZoneWindow::ZoneWindow(HINSTANCE hinstance) wcex.lpszClassName = NonLocalizable::ToolWindowClassName; wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); RegisterClassExW(&wcex); - - Gdiplus::GdiplusStartupInput gdiplusStartupInput; - Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); - m_paintExecutor.submit(OnThreadExecutor::task_t{ []() { BufferedPaintInit(); } }); } ZoneWindow::~ZoneWindow() { - Gdiplus::GdiplusShutdown(gdiplusToken); - m_paintExecutor.submit(OnThreadExecutor::task_t{ []() { BufferedPaintUnInit(); } }); } -bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, bool flashZones) +bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId) { m_host.copy_from(host); @@ -243,22 +183,6 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit MakeWindowTransparent(m_window.get()); m_zoneWindowDrawing = std::make_unique(m_window.get()); - // Ignore flashZones - /* - if (flashZones) - { - // Don't flash if the foreground window is in full screen mode - RECT windowRect; - if (!(GetWindowRect(GetForegroundWindow(), &windowRect) && - windowRect.left == mi.rcMonitor.left && - windowRect.top == mi.rcMonitor.top && - windowRect.right == mi.rcMonitor.right && - windowRect.bottom == mi.rcMonitor.bottom)) - { - FlashZones(); - } - } - */ return true; } @@ -409,10 +333,6 @@ ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept { InvalidateRect(m_window.get(), nullptr, true); } - else - { - FlashZones(); - } } IFACEMETHODIMP_(void) @@ -443,8 +363,6 @@ ZoneWindow::ShowZoneWindow() noexcept return; } - m_flashMode = false; - UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE; HWND windowInsertAfter = m_windowMoveSize; @@ -525,7 +443,7 @@ void ZoneWindow::CalculateZoneSet() noexcept activeZoneSet.type, m_monitor, sensitivityRadius)); - + RECT workArea; if (m_monitor) { @@ -548,9 +466,9 @@ void ZoneWindow::CalculateZoneSet() noexcept bool showSpacing = deviceInfoData->showSpacing; int spacing = showSpacing ? deviceInfoData->spacing : 0; int zoneCount = deviceInfoData->zoneCount; - + zoneSet->CalculateZones(workArea, zoneCount, spacing); - UpdateActiveZoneSet(zoneSet.get()); + UpdateActiveZoneSet(zoneSet.get()); } } @@ -586,11 +504,6 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept case WM_ERASEBKGND: return 1; - case WM_PRINTCLIENT: - { - // OnPaint(reinterpret_cast(wparam)); - } - break; case WM_PAINT: { OnPaintD2D(); @@ -605,52 +518,6 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept return 0; } -void ZoneWindow::OnPaint(HDC hdc) noexcept -{ - HWND window = m_window.get(); - bool hasActiveZoneSet = m_activeZoneSet && m_host; - COLORREF hostZoneColor{}; - COLORREF hostZoneBorderColor{}; - COLORREF hostZoneHighlightColor{}; - int hostZoneHighlightOpacity{}; - IZoneSet::ZonesMap zones; - std::vector highlightZone = m_highlightZone; - bool flashMode = m_flashMode; - - if (hasActiveZoneSet) - { - hostZoneColor = m_host->GetZoneColor(); - hostZoneBorderColor = m_host->GetZoneBorderColor(); - hostZoneHighlightColor = m_host->GetZoneHighlightColor(); - hostZoneHighlightOpacity = m_host->GetZoneHighlightOpacity(); - zones = m_activeZoneSet->GetZones(); - } - - OnThreadExecutor::task_t task{ - [=]() { - ZoneWindowUtils::PaintZoneWindow(hdc, - window, - hasActiveZoneSet, - hostZoneColor, - hostZoneBorderColor, - hostZoneHighlightColor, - hostZoneHighlightOpacity, - zones, - highlightZone, - flashMode); - } }; - - if (m_animating) - { - task(); - } - else - { - m_paintExecutor.cancel(); - m_paintExecutor.submit(std::move(task)); - } -} - void ZoneWindow::OnPaintD2D() noexcept { m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); @@ -726,21 +593,6 @@ void ZoneWindow::CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::Inp m_highlightZone = {}; } -void ZoneWindow::FlashZones() noexcept -{ - // "Turning FLASHING_ZONE option off" - if (true) - { - return; - } - - m_flashMode = true; - - ShowWindow(m_window.get(), SW_SHOWNA); - std::thread([window = m_window.get()]() { - AnimateWindow(window, m_flashDuration, AW_HIDE | AW_BLEND); - }).detach(); -} #pragma endregion LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept @@ -757,10 +609,10 @@ LRESULT CALLBACK ZoneWindow::s_WndProc(HWND window, UINT message, WPARAM wparam, DefWindowProc(window, message, wparam, lparam); } -winrt::com_ptr MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId, bool flashZones) noexcept +winrt::com_ptr MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId) noexcept { auto self = winrt::make_self(hinstance); - if (self->Init(host, hinstance, monitor, uniqueId, parentUniqueId, flashZones)) + if (self->Init(host, hinstance, monitor, uniqueId, parentUniqueId)) { return self; } diff --git a/src/modules/fancyzones/lib/ZoneWindow.h b/src/modules/fancyzones/lib/ZoneWindow.h index aeeb318f2..9eb70d9c7 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.h +++ b/src/modules/fancyzones/lib/ZoneWindow.h @@ -127,4 +127,4 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow }; winrt::com_ptr MakeZoneWindow(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, - const std::wstring& uniqueId, const std::wstring& parentUniqueId, bool flashZones) noexcept; + const std::wstring& uniqueId, const std::wstring& parentUniqueId) noexcept; diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index d18dc2868..e42da3ed3 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -10,156 +10,3 @@ namespace NonLocalizable { const wchar_t SegoeUiFont[] = L"Segoe ui"; } - -namespace -{ - void InitRGB(_Out_ RGBQUAD* quad, BYTE alpha, COLORREF color) - { - ZeroMemory(quad, sizeof(*quad)); - quad->rgbReserved = alpha; - quad->rgbRed = GetRValue(color) * alpha / 255; - quad->rgbGreen = GetGValue(color) * alpha / 255; - quad->rgbBlue = GetBValue(color) * alpha / 255; - } - - void FillRectARGB(wil::unique_hdc& hdc, RECT const* prcFill, BYTE alpha, COLORREF color, bool blendAlpha) - { - BITMAPINFO bi; - ZeroMemory(&bi, sizeof(bi)); - bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bi.bmiHeader.biWidth = 1; - bi.bmiHeader.biHeight = 1; - bi.bmiHeader.biPlanes = 1; - bi.bmiHeader.biBitCount = 32; - bi.bmiHeader.biCompression = BI_RGB; - - RECT fillRect; - CopyRect(&fillRect, prcFill); - - RGBQUAD bitmapBits; - InitRGB(&bitmapBits, alpha, color); - StretchDIBits( - hdc.get(), - fillRect.left, - fillRect.top, - fillRect.right - fillRect.left, - fillRect.bottom - fillRect.top, - 0, - 0, - 1, - 1, - &bitmapBits, - &bi, - DIB_RGB_COLORS, - SRCCOPY); - } - - BYTE OpacitySettingToAlpha(int opacity) - { - return static_cast(opacity * 2.55); - } - - void DrawIndex(wil::unique_hdc& hdc, FancyZonesUtils::Rect rect, size_t index) - { - Gdiplus::Graphics g(hdc.get()); - - Gdiplus::FontFamily fontFamily(NonLocalizable::SegoeUiFont); - Gdiplus::Font font(&fontFamily, 80, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); - Gdiplus::SolidBrush solidBrush(Gdiplus::Color(255, 0, 0, 0)); - - std::wstring text = std::to_wstring(index); - - g.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias); - Gdiplus::StringFormat stringFormat = new Gdiplus::StringFormat(); - stringFormat.SetAlignment(Gdiplus::StringAlignmentCenter); - stringFormat.SetLineAlignment(Gdiplus::StringAlignmentCenter); - - Gdiplus::RectF gdiRect(static_cast(rect.left()), - static_cast(rect.top()), - static_cast(rect.width()), - static_cast(rect.height())); - - g.DrawString(text.c_str(), -1, &font, gdiRect, &stringFormat, &solidBrush); - } - - void DrawZone(wil::unique_hdc& hdc, ZoneWindowDrawing::ColorSetting const& colorSetting, winrt::com_ptr zone, bool flashMode)noexcept - { - RECT zoneRect = zone->GetZoneRect(); - - Gdiplus::Graphics g(hdc.get()); - Gdiplus::Color fillColor(colorSetting.fillAlpha, GetRValue(colorSetting.fill), GetGValue(colorSetting.fill), GetBValue(colorSetting.fill)); - Gdiplus::Color borderColor(colorSetting.borderAlpha, GetRValue(colorSetting.border), GetGValue(colorSetting.border), GetBValue(colorSetting.border)); - - Gdiplus::Rect rectangle(zoneRect.left, zoneRect.top, zoneRect.right - zoneRect.left - 1, zoneRect.bottom - zoneRect.top - 1); - - Gdiplus::Pen pen(borderColor, static_cast(colorSetting.thickness)); - g.FillRectangle(new Gdiplus::SolidBrush(fillColor), rectangle); - g.DrawRectangle(&pen, rectangle); - - if (!flashMode) - { - DrawIndex(hdc, zoneRect, zone->Id() + 1); - } - } -} - -namespace ZoneWindowDrawingNS -{ - void DrawBackdrop(wil::unique_hdc& hdc, RECT const& clientRect) noexcept - { - FillRectARGB(hdc, &clientRect, 0, RGB(0, 0, 0), false); - } - - void DrawActiveZoneSet(wil::unique_hdc& hdc, - COLORREF zoneColor, - COLORREF zoneBorderColor, - COLORREF highlightColor, - int zoneOpacity, - const IZoneSet::ZonesMap& zones, - const std::vector& highlightZones, - bool flashMode) noexcept - { - // { fillAlpha, fill, borderAlpha, border, thickness } - ColorSetting colorViewer{ OpacitySettingToAlpha(zoneOpacity), 0, 255, RGB(40, 50, 60), -2 }; - ColorSetting colorHighlight{ OpacitySettingToAlpha(zoneOpacity), 0, 255, 0, -2 }; - ColorSetting const colorFlash{ OpacitySettingToAlpha(zoneOpacity), RGB(81, 92, 107), 200, RGB(104, 118, 138), -2 }; - - // First draw the inactive zones - for (auto iter = zones.begin(); iter != zones.end(); iter++) - { - winrt::com_ptr zone = iter->second; - size_t zoneId = zone->Id(); - if (!zone) - { - continue; - } - - auto zoneIt = std::find(highlightZones.begin(), highlightZones.end(), zoneId); - if (zoneIt == highlightZones.end()) - { - if (flashMode) - { - DrawZone(hdc, colorFlash, zone, flashMode); - } - else - { - colorViewer.fill = zoneColor; - colorViewer.border = zoneBorderColor; - DrawZone(hdc, colorViewer, zone, flashMode); - } - } - } - - // Draw the active zones on top of the inactive zones - for (const auto& zoneId : highlightZones) - { - colorHighlight.fill = highlightColor; - colorHighlight.border = zoneBorderColor; - - if (zones.contains(zoneId)) - { - DrawZone(hdc, colorHighlight, zones.at(zoneId), flashMode); - } - } - } -} diff --git a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp index 73c3a46c2..913fcf530 100644 --- a/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp +++ b/src/modules/fancyzones/tests/UnitTests/ZoneWindow.Spec.cpp @@ -114,7 +114,7 @@ namespace FancyZonesUnitTests TEST_METHOD(CreateZoneWindow) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); testZoneWindow(zoneWindow); auto* activeZoneSet{ zoneWindow->ActiveZoneSet() }; @@ -125,7 +125,7 @@ namespace FancyZonesUnitTests TEST_METHOD(CreateZoneWindowNoHinst) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), {}, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), {}, m_monitor, m_uniqueId.str(), {}); testZoneWindow(zoneWindow); auto* activeZoneSet{ zoneWindow->ActiveZoneSet() }; @@ -136,7 +136,7 @@ namespace FancyZonesUnitTests TEST_METHOD(CreateZoneWindowNoHinstFlashZones) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), {}, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), {}, m_monitor, m_uniqueId.str(), {}); testZoneWindow(zoneWindow); auto* activeZoneSet{ zoneWindow->ActiveZoneSet() }; @@ -147,13 +147,7 @@ namespace FancyZonesUnitTests TEST_METHOD(CreateZoneWindowNoMonitor) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, {}, m_uniqueId.str(), {}, false); - testZoneWindow(zoneWindow); - } - - TEST_METHOD(CreateZoneWindowNoMonitorFlashZones) - { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, {}, m_uniqueId.str(), {}, true); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, {}, m_uniqueId.str(), {}); testZoneWindow(zoneWindow); } @@ -161,7 +155,7 @@ namespace FancyZonesUnitTests { // Generate unique id without device id std::wstring uniqueId = ZoneWindowUtils::GenerateUniqueId(m_monitor, {}, m_virtualDesktopId); - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, uniqueId, {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, uniqueId, {}); const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom); const std::wstring expectedUniqueId = L"FallbackDevice_" + std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom) + L"_" + m_virtualDesktopId; @@ -179,7 +173,7 @@ namespace FancyZonesUnitTests { // Generate unique id without virtual desktop id std::wstring uniqueId = ZoneWindowUtils::GenerateUniqueId(m_monitor, m_deviceId, {}); - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, uniqueId, {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, uniqueId, {}); const std::wstring expectedWorkArea = std::to_wstring(m_monitorInfo.rcMonitor.right) + L"_" + std::to_wstring(m_monitorInfo.rcMonitor.bottom); Assert::IsNotNull(zoneWindow.get()); @@ -208,7 +202,7 @@ namespace FancyZonesUnitTests m_fancyZonesData.ParseDeviceInfoFromTmpFile(activeZoneSetTempPath); //temp file read on initialization - auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); testZoneWindow(actual); @@ -232,7 +226,7 @@ namespace FancyZonesUnitTests m_fancyZonesData.ParseDeviceInfoFromTmpFile(activeZoneSetTempPath); //temp file read on initialization - auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); testZoneWindow(actual); @@ -268,7 +262,7 @@ namespace FancyZonesUnitTests m_fancyZonesData.ParseCustomZoneSetFromTmpFile(appliedZoneSetTempPath); //temp file read on initialization - auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); testZoneWindow(actual); @@ -315,7 +309,7 @@ namespace FancyZonesUnitTests m_fancyZonesData.ParseCustomZoneSetFromTmpFile(appliedZoneSetTempPath); //temp file read on initialization - auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); testZoneWindow(actual); @@ -362,7 +356,7 @@ namespace FancyZonesUnitTests m_fancyZonesData.ParseCustomZoneSetFromTmpFile(appliedZoneSetTempPath); //temp file read on initialization - auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto actual = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); testZoneWindow(actual); @@ -384,11 +378,11 @@ namespace FancyZonesUnitTests m_fancyZonesData.SetDeviceInfo(m_parentUniqueId.str(), parentDeviceInfo); winrt::com_ptr zoneWindowHost = winrt::make_self(); - auto parentZoneWindow = MakeZoneWindow(zoneWindowHost.get(), m_hInst, m_monitor, m_parentUniqueId.str(), {}, false); + auto parentZoneWindow = MakeZoneWindow(zoneWindowHost.get(), m_hInst, m_monitor, m_parentUniqueId.str(), {}); zoneWindowHost->m_zoneWindow = parentZoneWindow.get(); // newWorkArea = true - zoneWindow will be cloned from parent - auto actualZoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), m_parentUniqueId.str(), false); + auto actualZoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), m_parentUniqueId.str()); Assert::IsNotNull(actualZoneWindow->ActiveZoneSet()); const auto actualZoneSet = actualZoneWindow->ActiveZoneSet()->GetZones(); @@ -414,11 +408,11 @@ namespace FancyZonesUnitTests m_fancyZonesData.SetDeviceInfo(m_parentUniqueId.str(), parentDeviceInfo); winrt::com_ptr zoneWindowHost = winrt::make_self(); - auto parentZoneWindow = MakeZoneWindow(zoneWindowHost.get(), m_hInst, m_monitor, m_parentUniqueId.str(), {}, false); + auto parentZoneWindow = MakeZoneWindow(zoneWindowHost.get(), m_hInst, m_monitor, m_parentUniqueId.str(), {}); zoneWindowHost->m_zoneWindow = parentZoneWindow.get(); // newWorkArea = false - zoneWindow won't be cloned from parent - auto actualZoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto actualZoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(actualZoneWindow->ActiveZoneSet()); @@ -475,7 +469,7 @@ namespace FancyZonesUnitTests public: TEST_METHOD(MoveSizeEnter) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto expected = S_OK; const auto actual = zoneWindow->MoveSizeEnter(Mocks::Window()); @@ -485,7 +479,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeEnterTwice) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto expected = S_OK; @@ -497,7 +491,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeUpdate) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto expected = S_OK; const auto actual = zoneWindow->MoveSizeUpdate(POINT{ 0, 0 }, true, false); @@ -507,7 +501,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeUpdatePointNegativeCoordinates) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto expected = S_OK; const auto actual = zoneWindow->MoveSizeUpdate(POINT{ -10, -10 }, true, false); @@ -517,7 +511,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeUpdatePointBigCoordinates) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto expected = S_OK; const auto actual = zoneWindow->MoveSizeUpdate(POINT{ m_monitorInfo.rcMonitor.right + 1, m_monitorInfo.rcMonitor.bottom + 1 }, true, false); @@ -527,7 +521,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeEnd) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto window = Mocks::Window(); zoneWindow->MoveSizeEnter(window); @@ -544,7 +538,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeEndWindowNotAdded) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto window = Mocks::Window(); zoneWindow->MoveSizeEnter(window); @@ -560,7 +554,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeEndDifferentWindows) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto window = Mocks::Window(); zoneWindow->MoveSizeEnter(window); @@ -573,7 +567,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeEndWindowNotSet) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto expected = E_INVALIDARG; const auto actual = zoneWindow->MoveSizeEnd(Mocks::Window(), POINT{ 0, 0 }); @@ -583,7 +577,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveSizeEndInvalidPoint) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); const auto window = Mocks::Window(); zoneWindow->MoveSizeEnter(window); @@ -600,7 +594,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveWindowIntoZoneByIndex) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(zoneWindow->ActiveZoneSet()); zoneWindow->MoveWindowIntoZoneByIndex(Mocks::Window(), 0); @@ -610,7 +604,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveWindowIntoZoneByDirectionAndIndex) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(zoneWindow->ActiveZoneSet()); const auto window = Mocks::WindowCreate(m_hInst); @@ -625,7 +619,7 @@ namespace FancyZonesUnitTests TEST_METHOD(MoveWindowIntoZoneByDirectionManyTimes) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(zoneWindow->ActiveZoneSet()); const auto window = Mocks::WindowCreate(m_hInst); @@ -642,7 +636,7 @@ namespace FancyZonesUnitTests TEST_METHOD(SaveWindowProcessToZoneIndexNullptrWindow) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(zoneWindow->ActiveZoneSet()); zoneWindow->SaveWindowProcessToZoneIndex(nullptr); @@ -653,7 +647,7 @@ namespace FancyZonesUnitTests TEST_METHOD(SaveWindowProcessToZoneIndexNoWindowAdded) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(zoneWindow->ActiveZoneSet()); auto window = Mocks::WindowCreate(m_hInst); @@ -668,7 +662,7 @@ namespace FancyZonesUnitTests TEST_METHOD(SaveWindowProcessToZoneIndexNoWindowAddedWithFilledAppZoneHistory) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(zoneWindow->ActiveZoneSet()); const auto window = Mocks::WindowCreate(m_hInst); @@ -696,7 +690,7 @@ namespace FancyZonesUnitTests TEST_METHOD(SaveWindowProcessToZoneIndexWindowAdded) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(zoneWindow->ActiveZoneSet()); auto window = Mocks::WindowCreate(m_hInst); @@ -726,7 +720,7 @@ namespace FancyZonesUnitTests TEST_METHOD(WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt) { - auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}, false); + auto zoneWindow = MakeZoneWindow(winrt::make_self().get(), m_hInst, m_monitor, m_uniqueId.str(), {}); Assert::IsNotNull(zoneWindow->ActiveZoneSet()); auto window = Mocks::WindowCreate(m_hInst); From 0925b479c22adffe4b8450aa3275629028bb7e3c Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Thu, 22 Oct 2020 23:51:45 +0200 Subject: [PATCH 07/22] Kinda works, but it's a bit laggy --- src/modules/fancyzones/lib/ZoneWindow.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index b2a74ab34..2c15f0a2e 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -109,7 +109,6 @@ private: void CalculateZoneSet() noexcept; void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept; LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; - void OnPaint(HDC hdc) noexcept; void OnPaintD2D() noexcept; void OnKeyUp(WPARAM wparam) noexcept; std::vector ZonesFromPoint(POINT pt) noexcept; @@ -236,6 +235,8 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable { InvalidateRect(m_window.get(), nullptr, true); } + + UpdateWindow(m_window.get()); return S_OK; } @@ -373,6 +374,8 @@ ZoneWindow::ShowZoneWindow() noexcept SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags); m_zoneWindowDrawing->Show(m_showAnimationDuration); + InvalidateRect(window, nullptr, true); + UpdateWindow(window); } IFACEMETHODIMP_(void) From ad4a6b3386dc7ecf4da8f23959222ec650016f45 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Fri, 23 Oct 2020 00:17:28 +0200 Subject: [PATCH 08/22] Works great, but needs refactoring/performance improvements --- src/modules/fancyzones/lib/ZoneWindow.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 2c15f0a2e..bda316c42 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -128,6 +128,8 @@ private: static const UINT m_showAnimationDuration = 200; // ms static const UINT m_flashDuration = 700; // ms std::unique_ptr m_zoneWindowDrawing; + + std::thread m_toy; }; ZoneWindow::ZoneWindow(HINSTANCE hinstance) @@ -183,6 +185,13 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit m_zoneWindowDrawing = std::make_unique(m_window.get()); + m_toy = std::thread([this]() { + while (1) + { + OnPaintD2D(); + } + }); + return true; } @@ -233,10 +242,10 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable if (redraw) { - InvalidateRect(m_window.get(), nullptr, true); + // InvalidateRect(m_window.get(), nullptr, true); } - UpdateWindow(m_window.get()); + // UpdateWindow(m_window.get()); return S_OK; } @@ -374,8 +383,6 @@ ZoneWindow::ShowZoneWindow() noexcept SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags); m_zoneWindowDrawing->Show(m_showAnimationDuration); - InvalidateRect(window, nullptr, true); - UpdateWindow(window); } IFACEMETHODIMP_(void) @@ -507,12 +514,6 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept case WM_ERASEBKGND: return 1; - case WM_PAINT: - { - OnPaintD2D(); - } - break; - default: { return DefWindowProc(m_window.get(), message, wparam, lparam); From 97ee0205e93ecfbe02ae61ae35badace1378ab1a Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Fri, 23 Oct 2020 14:37:14 +0200 Subject: [PATCH 09/22] Move code from .h to .cpp --- src/modules/fancyzones/lib/ZoneWindow.cpp | 9 - .../fancyzones/lib/ZoneWindowDrawing.cpp | 247 ++++++++++++++++ .../fancyzones/lib/ZoneWindowDrawing.h | 276 +----------------- 3 files changed, 258 insertions(+), 274 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index bda316c42..b177dcf51 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -128,8 +128,6 @@ private: static const UINT m_showAnimationDuration = 200; // ms static const UINT m_flashDuration = 700; // ms std::unique_ptr m_zoneWindowDrawing; - - std::thread m_toy; }; ZoneWindow::ZoneWindow(HINSTANCE hinstance) @@ -185,13 +183,6 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit m_zoneWindowDrawing = std::make_unique(m_window.get()); - m_toy = std::thread([this]() { - while (1) - { - OnPaintD2D(); - } - }); - return true; } diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index e42da3ed3..68ae482a0 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -10,3 +10,250 @@ namespace NonLocalizable { const wchar_t SegoeUiFont[] = L"Segoe ui"; } + +void ZoneWindowDrawing::DrawBackdrop() +{ + // Lock is being held + m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); +} + +float ZoneWindowDrawing::GetAnimationAlpha() +{ + // Lock is being held + if (!m_tAnimationStart) + { + return 1.f; + } + + auto tNow = std::chrono::steady_clock().now(); + auto alpha = (tNow - *m_tAnimationStart).count() / (1e6f * m_animationDuration); + if (alpha < 1.f) + { + return alpha; + } + else + { + return 1.f; + } +} + +ID2D1Factory* ZoneWindowDrawing::GetD2DFactory() +{ + static ID2D1Factory* pD2DFactory = nullptr; + if (!pD2DFactory) + { + D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &pD2DFactory); + } + return pD2DFactory; + + // TODO: Destroy factory +} + +IDWriteFactory* ZoneWindowDrawing::GetWriteFactory() +{ + static IUnknown* pDWriteFactory = nullptr; + if (!pDWriteFactory) + { + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &pDWriteFactory); + } + return reinterpret_cast(pDWriteFactory); + + // TODO: Destroy factory +} + +D2D1_COLOR_F ZoneWindowDrawing::ConvertColor(COLORREF color) +{ + return D2D1::ColorF(GetRValue(color) / 255.f, + GetGValue(color) / 255.f, + GetBValue(color) / 255.f, + 1.f); +} + +D2D1_RECT_F ZoneWindowDrawing::ConvertRect(RECT rect) +{ + return D2D1::RectF((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom); +} + +ZoneWindowDrawing::ZoneWindowDrawing(HWND window) +{ + m_window = window; + m_renderTarget = nullptr; + m_animationDuration = 0; + + // Obtain the size of the drawing area. + if (!GetClientRect(window, &m_clientRect)) + { + return; + } + + // Create a Direct2D render target + GetD2DFactory()->CreateHwndRenderTarget( + D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)), + D2D1::HwndRenderTargetProperties( + window, + D2D1::SizeU( + m_clientRect.right - m_clientRect.left, + m_clientRect.bottom - m_clientRect.top)), + &m_renderTarget); +} + +void ZoneWindowDrawing::Render() +{ + std::unique_lock lock(m_mutex); + + if (!m_renderTarget) + { + return; + } + + m_renderTarget->BeginDraw(); + DrawBackdrop(); + float animationAlpha = GetAnimationAlpha(); + + for (auto drawableRect : m_sceneRects) + { + ID2D1SolidColorBrush* borderBrush = nullptr; + ID2D1SolidColorBrush* fillBrush = nullptr; + ID2D1SolidColorBrush* textBrush = nullptr; + + // Need to copy the rect from m_sceneRects + drawableRect.borderColor.a *= animationAlpha; + drawableRect.fillColor.a *= animationAlpha; + + m_renderTarget->CreateSolidColorBrush(drawableRect.borderColor, &borderBrush); + m_renderTarget->CreateSolidColorBrush(drawableRect.fillColor, &fillBrush); + m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, animationAlpha), &textBrush); + + if (fillBrush) + { + m_renderTarget->FillRectangle(drawableRect.rect, fillBrush); + fillBrush->Release(); + } + + if (borderBrush) + { + m_renderTarget->DrawRectangle(drawableRect.rect, borderBrush); + borderBrush->Release(); + } + + std::wstring idStr = std::to_wstring(drawableRect.id); + + IDWriteTextFormat* textFormat = nullptr; + auto writeFactory = GetWriteFactory(); + + if (writeFactory) + { + writeFactory->CreateTextFormat(NonLocalizable::SegoeUiFont, nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 80.f, L"en-US", &textFormat); + } + + if (textFormat && textBrush) + { + textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); + textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + m_renderTarget->DrawTextW(idStr.c_str(), (UINT32)idStr.size(), textFormat, drawableRect.rect, textBrush); + } + + if (textFormat) + { + textFormat->Release(); + } + + if (textBrush) + { + textBrush->Release(); + } + } + + m_renderTarget->EndDraw(); +} + +void ZoneWindowDrawing::Hide() +{ + std::unique_lock lock(m_mutex); + if (m_tAnimationStart) + { + m_tAnimationStart.reset(); + ShowWindow(m_window, SW_HIDE); + } +} + +void ZoneWindowDrawing::Show(unsigned animationMillis) +{ + std::unique_lock lock(m_mutex); + if (!m_tAnimationStart) + { + ShowWindow(m_window, SW_SHOWDEFAULT); + m_tAnimationStart = std::chrono::steady_clock().now(); + m_animationDuration = animationMillis; + } +} + +void ZoneWindowDrawing::DrawActiveZoneSet(const std::vector>& zones, + const std::vector& highlightZones, + winrt::com_ptr host) +{ + std::unique_lock lock(m_mutex); + + m_sceneRects = {}; + + auto borderColor = ConvertColor(host->GetZoneBorderColor()); + auto inactiveColor = ConvertColor(host->GetZoneColor()); + auto highlightColor = ConvertColor(host->GetZoneHighlightColor()); + + inactiveColor.a = host->GetZoneHighlightOpacity() / 100.f; + highlightColor.a = host->GetZoneHighlightOpacity() / 100.f; + + std::vector isHighlighted(zones.size(), false); + for (size_t x : highlightZones) + { + isHighlighted[x] = true; + } + + // First draw the inactive zones + for (auto iter = zones.begin(); iter != zones.end(); iter++) + { + int zoneId = static_cast(iter - zones.begin()); + winrt::com_ptr zone = iter->try_as(); + if (!zone) + { + continue; + } + + if (!isHighlighted[zoneId]) + { + DrawableRect drawableRect{ + .rect = ConvertRect(zone->GetZoneRect()), + .borderColor = borderColor, + .fillColor = inactiveColor, + .id = zone->Id() + }; + + m_sceneRects.push_back(drawableRect); + } + } + + // Draw the active zones on top of the inactive zones + for (auto iter = zones.begin(); iter != zones.end(); iter++) + { + int zoneId = static_cast(iter - zones.begin()); + winrt::com_ptr zone = iter->try_as(); + if (!zone) + { + continue; + } + + if (isHighlighted[zoneId]) + { + DrawableRect drawableRect{ + .rect = ConvertRect(zone->GetZoneRect()), + .borderColor = borderColor, + .fillColor = highlightColor, + .id = zone->Id() + }; + + m_sceneRects.push_back(drawableRect); + } + } +} diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index 693e23df2..d6472d2ad 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -11,28 +11,6 @@ #include "Zone.h" #include "ZoneSet.h" -namespace ZoneWindowDrawingNS -{ - struct ColorSetting - { - BYTE fillAlpha{}; - COLORREF fill{}; - BYTE borderAlpha{}; - COLORREF border{}; - int thickness{}; - }; - - void DrawBackdrop(wil::unique_hdc& hdc, RECT const& clientRect) noexcept; - void DrawActiveZoneSet(wil::unique_hdc& hdc, - COLORREF zoneColor, - COLORREF zoneBorderColor, - COLORREF highlightColor, - int zoneOpacity, - const IZoneSet::ZonesMap& zones, - const std::vector& highlightZones, - bool flashMode) noexcept; -} - class ZoneWindowDrawing { struct DrawableRect @@ -53,252 +31,20 @@ class ZoneWindowDrawing std::mutex m_mutex; std::vector m_sceneRects; - void DrawBackdrop() - { - // Lock is being held - m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); - } - - float GetAnimationAlpha() - { - // Lock is being held - if (!m_tAnimationStart) - { - return 1.f; - } - - auto tNow = std::chrono::steady_clock().now(); - auto alpha = (tNow - *m_tAnimationStart).count() / (1e6f * m_animationDuration); - if (alpha < 1.f) - { - return alpha; - } - else - { - return 1.f; - } - } - - static ID2D1Factory* GetD2DFactory() - { - static ID2D1Factory* pD2DFactory = nullptr; - if (!pD2DFactory) - { - D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &pD2DFactory); - } - return pD2DFactory; - - // TODO: Destroy factory - } - - static IDWriteFactory* GetWriteFactory() - { - static IUnknown* pDWriteFactory = nullptr; - if (!pDWriteFactory) - { - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &pDWriteFactory); - } - return reinterpret_cast(pDWriteFactory); - - // TODO: Destroy factory - } - - static D2D1_COLOR_F ConvertColor(COLORREF color) - { - return D2D1::ColorF(GetRValue(color) / 255.f, - GetGValue(color) / 255.f, - GetBValue(color) / 255.f, - 1.f); - } - - static D2D1_RECT_F ConvertRect(RECT rect) - { - return D2D1::RectF((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom); - } + void DrawBackdrop(); + float GetAnimationAlpha(); + static ID2D1Factory* GetD2DFactory(); + static IDWriteFactory* GetWriteFactory(); + static D2D1_COLOR_F ConvertColor(COLORREF color); + static D2D1_RECT_F ConvertRect(RECT rect); public: - ZoneWindowDrawing(HWND window) - { - m_window = window; - m_renderTarget = nullptr; - m_animationDuration = 0; - - // Obtain the size of the drawing area. - if (!GetClientRect(window, &m_clientRect)) - { - return; - } - - // Create a Direct2D render target - GetD2DFactory()->CreateHwndRenderTarget( - D2D1::RenderTargetProperties( - D2D1_RENDER_TARGET_TYPE_DEFAULT, - D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)), - D2D1::HwndRenderTargetProperties( - window, - D2D1::SizeU( - m_clientRect.right - m_clientRect.left, - m_clientRect.bottom - m_clientRect.top)), - &m_renderTarget); - } - - void Render() - { - std::unique_lock lock(m_mutex); - - if (!m_renderTarget) - { - return; - } - - m_renderTarget->BeginDraw(); - DrawBackdrop(); - float animationAlpha = GetAnimationAlpha(); - - for (auto drawableRect : m_sceneRects) - { - ID2D1SolidColorBrush* borderBrush = nullptr; - ID2D1SolidColorBrush* fillBrush = nullptr; - ID2D1SolidColorBrush* textBrush = nullptr; - - // Need to copy the rect from m_sceneRects - drawableRect.borderColor.a *= animationAlpha; - drawableRect.fillColor.a *= animationAlpha; - - m_renderTarget->CreateSolidColorBrush(drawableRect.borderColor, &borderBrush); - m_renderTarget->CreateSolidColorBrush(drawableRect.fillColor, &fillBrush); - m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, animationAlpha), &textBrush); - - if (fillBrush) - { - m_renderTarget->FillRectangle(drawableRect.rect, fillBrush); - fillBrush->Release(); - } - - if (borderBrush) - { - m_renderTarget->DrawRectangle(drawableRect.rect, borderBrush); - borderBrush->Release(); - } - - std::wstring idStr = std::to_wstring(drawableRect.id); - - // TODO: mark string as non-localizable - IDWriteTextFormat* textFormat = nullptr; - auto writeFactory = GetWriteFactory(); - - if (writeFactory) - { - writeFactory->CreateTextFormat(L"Segoe ui", nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 80.f, L"en-US", &textFormat); - } - - if (textFormat && textBrush) - { - textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); - textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); - m_renderTarget->DrawTextW(idStr.c_str(), (UINT32)idStr.size(), textFormat, drawableRect.rect, textBrush); - } - - if (textFormat) - { - textFormat->Release(); - } - - if (textBrush) - { - textBrush->Release(); - } - } - - m_renderTarget->EndDraw(); - } - - void Hide() - { - std::unique_lock lock(m_mutex); - if (m_tAnimationStart) - { - m_tAnimationStart.reset(); - ShowWindow(m_window, SW_HIDE); - } - } - - void Show(unsigned animationMillis) - { - std::unique_lock lock(m_mutex); - if (!m_tAnimationStart) - { - ShowWindow(m_window, SW_SHOWDEFAULT); - m_tAnimationStart = std::chrono::steady_clock().now(); - m_animationDuration = animationMillis; - } - } + ZoneWindowDrawing(HWND window); + void Render(); + void Hide(); + void Show(unsigned animationMillis); void DrawActiveZoneSet(const std::vector>& zones, const std::vector& highlightZones, - winrt::com_ptr host) - { - std::unique_lock lock(m_mutex); - - m_sceneRects = {}; - - auto borderColor = ConvertColor(host->GetZoneBorderColor()); - auto inactiveColor = ConvertColor(host->GetZoneColor()); - auto highlightColor = ConvertColor(host->GetZoneHighlightColor()); - - inactiveColor.a = host->GetZoneHighlightOpacity() / 100.f; - highlightColor.a = host->GetZoneHighlightOpacity() / 100.f; - - std::vector isHighlighted(zones.size(), false); - for (size_t x : highlightZones) - { - isHighlighted[x] = true; - } - - // First draw the inactive zones - for (auto iter = zones.begin(); iter != zones.end(); iter++) - { - int zoneId = static_cast(iter - zones.begin()); - winrt::com_ptr zone = iter->try_as(); - if (!zone) - { - continue; - } - - if (!isHighlighted[zoneId]) - { - DrawableRect drawableRect{ - .rect = ConvertRect(zone->GetZoneRect()), - .borderColor = borderColor, - .fillColor = inactiveColor, - .id = zone->Id() - }; - - m_sceneRects.push_back(drawableRect); - } - } - - // Draw the active zones on top of the inactive zones - for (auto iter = zones.begin(); iter != zones.end(); iter++) - { - int zoneId = static_cast(iter - zones.begin()); - winrt::com_ptr zone = iter->try_as(); - if (!zone) - { - continue; - } - - if (isHighlighted[zoneId]) - { - DrawableRect drawableRect{ - .rect = ConvertRect(zone->GetZoneRect()), - .borderColor = borderColor, - .fillColor = highlightColor, - .id = zone->Id() - }; - - m_sceneRects.push_back(drawableRect); - } - } - } + winrt::com_ptr host); }; From 1390bf271f58fe9ad2596778e51518d773706d4a Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Fri, 23 Oct 2020 15:22:45 +0200 Subject: [PATCH 10/22] Polished the functionality --- src/modules/fancyzones/lib/ZoneWindow.cpp | 17 +++-- .../fancyzones/lib/ZoneWindowDrawing.cpp | 70 ++++++++++++++++--- .../fancyzones/lib/ZoneWindowDrawing.h | 12 +++- 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index b177dcf51..9afb366f0 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -109,7 +109,6 @@ private: void CalculateZoneSet() noexcept; void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept; LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; - void OnPaintD2D() noexcept; void OnKeyUp(WPARAM wparam) noexcept; std::vector ZonesFromPoint(POINT pt) noexcept; void CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept; @@ -233,10 +232,9 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable if (redraw) { - // InvalidateRect(m_window.get(), nullptr, true); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); } - // UpdateWindow(m_window.get()); return S_OK; } @@ -374,6 +372,7 @@ ZoneWindow::ShowZoneWindow() noexcept SetWindowPos(window, windowInsertAfter, 0, 0, 0, 0, flags); m_zoneWindowDrawing->Show(m_showAnimationDuration); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); } IFACEMETHODIMP_(void) @@ -505,6 +504,12 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept case WM_ERASEBKGND: return 1; + case WM_PAINT: + { + m_zoneWindowDrawing->ForceRender(); + break; + } + default: { return DefWindowProc(m_window.get(), message, wparam, lparam); @@ -513,12 +518,6 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept return 0; } -void ZoneWindow::OnPaintD2D() noexcept -{ - m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); - m_zoneWindowDrawing->Render(); -} - void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept { bool fRedraw = false; diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 68ae482a0..143a7cfa0 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -11,12 +11,6 @@ namespace NonLocalizable const wchar_t SegoeUiFont[] = L"Segoe ui"; } -void ZoneWindowDrawing::DrawBackdrop() -{ - // Lock is being held - m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); -} - float ZoneWindowDrawing::GetAnimationAlpha() { // Lock is being held @@ -79,6 +73,7 @@ ZoneWindowDrawing::ZoneWindowDrawing(HWND window) m_window = window; m_renderTarget = nullptr; m_animationDuration = 0; + m_shouldRender = false; // Obtain the size of the drawing area. if (!GetClientRect(window, &m_clientRect)) @@ -97,6 +92,29 @@ ZoneWindowDrawing::ZoneWindowDrawing(HWND window) m_clientRect.right - m_clientRect.left, m_clientRect.bottom - m_clientRect.top)), &m_renderTarget); + + m_renderThread = std::thread([this]() { + while (!m_abortThread) + { + // Force repeated rendering while in the animation loop. + // Yield if low latency locking was requested + if (!m_lowLatencyLock) + { + float animationAlpha; + { + std::unique_lock lock(m_mutex); + animationAlpha = GetAnimationAlpha(); + } + + if (animationAlpha < 1.f) + { + m_shouldRender = true; + } + } + + Render(); + } + }); } void ZoneWindowDrawing::Render() @@ -108,10 +126,15 @@ void ZoneWindowDrawing::Render() return; } + m_cv.wait(lock, [this]() { return (bool)m_shouldRender; }); + m_renderTarget->BeginDraw(); - DrawBackdrop(); + float animationAlpha = GetAnimationAlpha(); + // Draw backdrop + m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); + for (auto drawableRect : m_sceneRects) { ID2D1SolidColorBrush* borderBrush = nullptr; @@ -167,6 +190,7 @@ void ZoneWindowDrawing::Render() } m_renderTarget->EndDraw(); + m_shouldRender = false; } void ZoneWindowDrawing::Hide() @@ -181,12 +205,17 @@ void ZoneWindowDrawing::Hide() void ZoneWindowDrawing::Show(unsigned animationMillis) { + m_lowLatencyLock = true; std::unique_lock lock(m_mutex); + m_lowLatencyLock = false; + if (!m_tAnimationStart) { ShowWindow(m_window, SW_SHOWDEFAULT); m_tAnimationStart = std::chrono::steady_clock().now(); - m_animationDuration = animationMillis; + m_animationDuration = max(1u, animationMillis); + m_shouldRender = true; + m_cv.notify_all(); } } @@ -194,7 +223,9 @@ void ZoneWindowDrawing::DrawActiveZoneSet(const std::vector& highlightZones, winrt::com_ptr host) { + m_lowLatencyLock = true; std::unique_lock lock(m_mutex); + m_lowLatencyLock = false; m_sceneRects = {}; @@ -256,4 +287,27 @@ void ZoneWindowDrawing::DrawActiveZoneSet(const std::vector m_sceneRects; - void DrawBackdrop(); float GetAnimationAlpha(); static ID2D1Factory* GetD2DFactory(); static IDWriteFactory* GetWriteFactory(); static D2D1_COLOR_F ConvertColor(COLORREF color); static D2D1_RECT_F ConvertRect(RECT rect); + void Render(); + void StopRendering(); + + std::atomic m_shouldRender; + std::atomic m_abortThread; + std::atomic m_lowLatencyLock; + std::condition_variable m_cv; + std::thread m_renderThread; public: + ~ZoneWindowDrawing(); ZoneWindowDrawing(HWND window); - void Render(); void Hide(); void Show(unsigned animationMillis); + void ForceRender(); void DrawActiveZoneSet(const std::vector>& zones, const std::vector& highlightZones, winrt::com_ptr host); From 3b1a70c10a302b747e52b6660aa37962cd3793c9 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Fri, 23 Oct 2020 15:32:51 +0200 Subject: [PATCH 11/22] Fix issue with changing monitors --- src/modules/fancyzones/lib/ZoneWindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 9afb366f0..672a77723 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -399,7 +399,7 @@ ZoneWindow::ClearSelectedZones() noexcept if (m_highlightZone.size()) { m_highlightZone.clear(); - InvalidateRect(m_window.get(), nullptr, true); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); } } @@ -526,7 +526,7 @@ void ZoneWindow::OnKeyUp(WPARAM wparam) noexcept if ((wparam >= '0') && (wparam <= '9')) { CycleActiveZoneSetInternal(static_cast(wparam), Trace::ZoneWindow::InputMode::Keyboard); - InvalidateRect(m_window.get(), nullptr, true); + m_zoneWindowDrawing->DrawActiveZoneSet(m_activeZoneSet->GetZones(), m_highlightZone, m_host); } } From 51faca5b6964171cd16e37d4772cebbde134fc23 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Mon, 26 Oct 2020 12:20:01 +0100 Subject: [PATCH 12/22] Rebase fix --- src/modules/fancyzones/lib/ZoneWindowDrawing.cpp | 12 ++++-------- src/modules/fancyzones/lib/ZoneWindowDrawing.h | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 143a7cfa0..4a9f61c20 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -219,7 +219,7 @@ void ZoneWindowDrawing::Show(unsigned animationMillis) } } -void ZoneWindowDrawing::DrawActiveZoneSet(const std::vector>& zones, +void ZoneWindowDrawing::DrawActiveZoneSet(const IZoneSet::ZonesMap& zones, const std::vector& highlightZones, winrt::com_ptr host) { @@ -236,17 +236,15 @@ void ZoneWindowDrawing::DrawActiveZoneSet(const std::vectorGetZoneHighlightOpacity() / 100.f; highlightColor.a = host->GetZoneHighlightOpacity() / 100.f; - std::vector isHighlighted(zones.size(), false); + std::vector isHighlighted(zones.size() + 1, false); for (size_t x : highlightZones) { isHighlighted[x] = true; } // First draw the inactive zones - for (auto iter = zones.begin(); iter != zones.end(); iter++) + for (const auto& [zoneId, zone] : zones) { - int zoneId = static_cast(iter - zones.begin()); - winrt::com_ptr zone = iter->try_as(); if (!zone) { continue; @@ -266,10 +264,8 @@ void ZoneWindowDrawing::DrawActiveZoneSet(const std::vector(iter - zones.begin()); - winrt::com_ptr zone = iter->try_as(); if (!zone) { continue; diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index 4c0e73652..dbd3d96b9 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -52,7 +52,7 @@ public: void Hide(); void Show(unsigned animationMillis); void ForceRender(); - void DrawActiveZoneSet(const std::vector>& zones, + void DrawActiveZoneSet(const IZoneSet::ZonesMap& zones, const std::vector& highlightZones, winrt::com_ptr host); }; From 191c5c3b37a3f2c96234d8c9057758ab1e0f0899 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Mon, 26 Oct 2020 12:23:56 +0100 Subject: [PATCH 13/22] Finalize PR before review --- src/modules/fancyzones/lib/ZoneWindowDrawing.cpp | 4 ---- src/modules/fancyzones/lib/ZoneWindowDrawing.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 4a9f61c20..86151f603 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -39,8 +39,6 @@ ID2D1Factory* ZoneWindowDrawing::GetD2DFactory() D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &pD2DFactory); } return pD2DFactory; - - // TODO: Destroy factory } IDWriteFactory* ZoneWindowDrawing::GetWriteFactory() @@ -51,8 +49,6 @@ IDWriteFactory* ZoneWindowDrawing::GetWriteFactory() DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &pDWriteFactory); } return reinterpret_cast(pDWriteFactory); - - // TODO: Destroy factory } D2D1_COLOR_F ZoneWindowDrawing::ConvertColor(COLORREF color) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index dbd3d96b9..f5602edf4 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -23,7 +23,6 @@ class ZoneWindowDrawing HWND m_window; RECT m_clientRect; - // winrt::com_ptr m_host; ID2D1HwndRenderTarget* m_renderTarget; std::optional m_tAnimationStart; unsigned m_animationDuration; @@ -37,7 +36,6 @@ class ZoneWindowDrawing static D2D1_COLOR_F ConvertColor(COLORREF color); static D2D1_RECT_F ConvertRect(RECT rect); void Render(); - void StopRendering(); std::atomic m_shouldRender; std::atomic m_abortThread; From d09e03d7f231f5f0e1ce04be3b856604a92c6a68 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Mon, 26 Oct 2020 17:37:56 +0100 Subject: [PATCH 14/22] Couple two members of ZoneWindowDrawing --- .../fancyzones/lib/ZoneWindowDrawing.cpp | 17 +++++++++-------- src/modules/fancyzones/lib/ZoneWindowDrawing.h | 9 +++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 86151f603..79ffad234 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -14,13 +14,13 @@ namespace NonLocalizable float ZoneWindowDrawing::GetAnimationAlpha() { // Lock is being held - if (!m_tAnimationStart) + if (!m_animation) { return 1.f; } auto tNow = std::chrono::steady_clock().now(); - auto alpha = (tNow - *m_tAnimationStart).count() / (1e6f * m_animationDuration); + auto alpha = (tNow - m_animation->tStart).count() / (1e6f * m_animation->duration); if (alpha < 1.f) { return alpha; @@ -68,7 +68,6 @@ ZoneWindowDrawing::ZoneWindowDrawing(HWND window) { m_window = window; m_renderTarget = nullptr; - m_animationDuration = 0; m_shouldRender = false; // Obtain the size of the drawing area. @@ -192,9 +191,9 @@ void ZoneWindowDrawing::Render() void ZoneWindowDrawing::Hide() { std::unique_lock lock(m_mutex); - if (m_tAnimationStart) + if (m_animation) { - m_tAnimationStart.reset(); + m_animation.reset(); ShowWindow(m_window, SW_HIDE); } } @@ -205,11 +204,13 @@ void ZoneWindowDrawing::Show(unsigned animationMillis) std::unique_lock lock(m_mutex); m_lowLatencyLock = false; - if (!m_tAnimationStart) + if (!m_animation) { ShowWindow(m_window, SW_SHOWDEFAULT); - m_tAnimationStart = std::chrono::steady_clock().now(); - m_animationDuration = max(1u, animationMillis); + if (animationMillis > 0) + { + m_animation.emplace(AnimationInfo{ std::chrono::steady_clock().now(), animationMillis }); + } m_shouldRender = true; m_cv.notify_all(); } diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index f5602edf4..12dc92d3e 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -21,11 +21,16 @@ class ZoneWindowDrawing size_t id; }; + struct AnimationInfo + { + std::chrono::steady_clock::time_point tStart; + unsigned duration; + }; + HWND m_window; RECT m_clientRect; ID2D1HwndRenderTarget* m_renderTarget; - std::optional m_tAnimationStart; - unsigned m_animationDuration; + std::optional m_animation; std::mutex m_mutex; std::vector m_sceneRects; From d5ef0b13303c45358fa7306d70971a1a797c5008 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 27 Oct 2020 02:13:54 +0100 Subject: [PATCH 15/22] Also request a low latency lock when hiding the zone window --- src/modules/fancyzones/lib/ZoneWindowDrawing.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 79ffad234..d71dabf34 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -190,7 +190,10 @@ void ZoneWindowDrawing::Render() void ZoneWindowDrawing::Hide() { + m_lowLatencyLock = true; std::unique_lock lock(m_mutex); + m_lowLatencyLock = false; + if (m_animation) { m_animation.reset(); From 6c05d116a092ab32f3451c2c29ba49ddba96f75c Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 27 Oct 2020 11:05:12 +0100 Subject: [PATCH 16/22] Move textFormat and textBrush out of the loop --- .../fancyzones/lib/ZoneWindowDrawing.cpp | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index d71dabf34..89ce1c24a 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -130,11 +130,21 @@ void ZoneWindowDrawing::Render() // Draw backdrop m_renderTarget->Clear(D2D1::ColorF(0.f, 0.f, 0.f, 0.f)); + ID2D1SolidColorBrush* textBrush = nullptr; + IDWriteTextFormat* textFormat = nullptr; + + m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, animationAlpha), &textBrush); + auto writeFactory = GetWriteFactory(); + + if (writeFactory) + { + writeFactory->CreateTextFormat(NonLocalizable::SegoeUiFont, nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 80.f, L"en-US", &textFormat); + } + for (auto drawableRect : m_sceneRects) { ID2D1SolidColorBrush* borderBrush = nullptr; ID2D1SolidColorBrush* fillBrush = nullptr; - ID2D1SolidColorBrush* textBrush = nullptr; // Need to copy the rect from m_sceneRects drawableRect.borderColor.a *= animationAlpha; @@ -142,7 +152,6 @@ void ZoneWindowDrawing::Render() m_renderTarget->CreateSolidColorBrush(drawableRect.borderColor, &borderBrush); m_renderTarget->CreateSolidColorBrush(drawableRect.fillColor, &fillBrush); - m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, animationAlpha), &textBrush); if (fillBrush) { @@ -158,30 +167,22 @@ void ZoneWindowDrawing::Render() std::wstring idStr = std::to_wstring(drawableRect.id); - IDWriteTextFormat* textFormat = nullptr; - auto writeFactory = GetWriteFactory(); - - if (writeFactory) - { - writeFactory->CreateTextFormat(NonLocalizable::SegoeUiFont, nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 80.f, L"en-US", &textFormat); - } - if (textFormat && textBrush) { textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); m_renderTarget->DrawTextW(idStr.c_str(), (UINT32)idStr.size(), textFormat, drawableRect.rect, textBrush); } + } - if (textFormat) - { - textFormat->Release(); - } + if (textFormat) + { + textFormat->Release(); + } - if (textBrush) - { - textBrush->Release(); - } + if (textBrush) + { + textBrush->Release(); } m_renderTarget->EndDraw(); From bb8ee18a597fc71ff78bec7226ba6b732643be3d Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 27 Oct 2020 11:11:23 +0100 Subject: [PATCH 17/22] Thread-safe initialization --- .../fancyzones/lib/ZoneWindowDrawing.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 89ce1c24a..73221ef72 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -33,22 +33,22 @@ float ZoneWindowDrawing::GetAnimationAlpha() ID2D1Factory* ZoneWindowDrawing::GetD2DFactory() { - static ID2D1Factory* pD2DFactory = nullptr; - if (!pD2DFactory) - { - D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &pD2DFactory); - } + static auto pD2DFactory = [] { + ID2D1Factory* res = nullptr; + D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &res); + return res; + }(); return pD2DFactory; } IDWriteFactory* ZoneWindowDrawing::GetWriteFactory() { - static IUnknown* pDWriteFactory = nullptr; - if (!pDWriteFactory) - { - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &pDWriteFactory); - } - return reinterpret_cast(pDWriteFactory); + static auto pDWriteFactory = [] { + IUnknown* res = nullptr; + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &res); + return reinterpret_cast(res); + }(); + return pDWriteFactory; } D2D1_COLOR_F ZoneWindowDrawing::ConvertColor(COLORREF color) From 9fd8d831ca6bf6771c6fb66feff5871086fb8cc7 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 27 Oct 2020 15:32:24 +0100 Subject: [PATCH 18/22] Rebase fix: zone numbers --- src/modules/fancyzones/lib/ZoneWindowDrawing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 73221ef72..6252c3bf1 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -165,7 +165,7 @@ void ZoneWindowDrawing::Render() borderBrush->Release(); } - std::wstring idStr = std::to_wstring(drawableRect.id); + std::wstring idStr = std::to_wstring(drawableRect.id + 1); if (textFormat && textBrush) { From 10052a6d7e0b67cc812ceedc031dd06538ff6a8d Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 27 Oct 2020 15:37:12 +0100 Subject: [PATCH 19/22] Make zone borders crispy --- src/modules/fancyzones/lib/ZoneWindowDrawing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 6252c3bf1..e8411d910 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -61,7 +61,7 @@ D2D1_COLOR_F ZoneWindowDrawing::ConvertColor(COLORREF color) D2D1_RECT_F ZoneWindowDrawing::ConvertRect(RECT rect) { - return D2D1::RectF((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom); + return D2D1::RectF((float)rect.left + 0.5f, (float)rect.top + 0.5f, (float)rect.right + 0.5f, (float)rect.bottom + 0.5f); } ZoneWindowDrawing::ZoneWindowDrawing(HWND window) From 9a60892b68b582459d75523842e287dbdd35df13 Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Tue, 27 Oct 2020 15:38:41 +0100 Subject: [PATCH 20/22] Fix offsets --- src/modules/fancyzones/lib/ZoneWindowDrawing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index e8411d910..5fa7037f4 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -61,7 +61,7 @@ D2D1_COLOR_F ZoneWindowDrawing::ConvertColor(COLORREF color) D2D1_RECT_F ZoneWindowDrawing::ConvertRect(RECT rect) { - return D2D1::RectF((float)rect.left + 0.5f, (float)rect.top + 0.5f, (float)rect.right + 0.5f, (float)rect.bottom + 0.5f); + return D2D1::RectF((float)rect.left + 0.5f, (float)rect.top + 0.5f, (float)rect.right - 0.5f, (float)rect.bottom - 0.5f); } ZoneWindowDrawing::ZoneWindowDrawing(HWND window) From 3ede9359494eea19c63c2bc6285fe27c75ed015d Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Wed, 28 Oct 2020 14:30:17 +0100 Subject: [PATCH 21/22] Another rebase fix --- src/modules/fancyzones/lib/ZoneWindowDrawing.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.h b/src/modules/fancyzones/lib/ZoneWindowDrawing.h index 12dc92d3e..879452430 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.h +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.h @@ -10,6 +10,7 @@ #include "util.h" #include "Zone.h" #include "ZoneSet.h" +#include "FancyZones.h" class ZoneWindowDrawing { From 39982f1eecc16db298d135dacf51fcd2208d46cc Mon Sep 17 00:00:00 2001 From: ivan100sic Date: Wed, 28 Oct 2020 15:50:42 +0100 Subject: [PATCH 22/22] Fix DPI bug --- src/modules/fancyzones/lib/ZoneWindowDrawing.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp index 5fa7037f4..b90186bd9 100644 --- a/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp +++ b/src/modules/fancyzones/lib/ZoneWindowDrawing.cpp @@ -77,10 +77,13 @@ ZoneWindowDrawing::ZoneWindowDrawing(HWND window) } // Create a Direct2D render target + // We should always use the DPI value of 96 since we're running in DPI aware mode GetD2DFactory()->CreateHwndRenderTarget( D2D1::RenderTargetProperties( D2D1_RENDER_TARGET_TYPE_DEFAULT, - D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)), + D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED), + 96.f, + 96.f), D2D1::HwndRenderTargetProperties( window, D2D1::SizeU(