From 6161531376f81a29cfaa70e588df6dedd59e6ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Sto=C5=A1i=C4=87?= Date: Mon, 12 Oct 2020 11:05:22 +0200 Subject: [PATCH] [FancyZones] Responsive drawing (#7125) * Made drawing zones not clog message processing * Fixed synchronization bugs * call BufferedPaintInit * Some refactoring, the animation is back * Rename a function * Align parameters --- src/common/on_thread_executor.cpp | 8 ++ src/common/on_thread_executor.h | 1 + src/modules/fancyzones/lib/ZoneWindow.cpp | 139 ++++++++++++++++------ 3 files changed, 112 insertions(+), 36 deletions(-) diff --git a/src/common/on_thread_executor.cpp b/src/common/on_thread_executor.cpp index e5a55ffe16..3498e341a8 100644 --- a/src/common/on_thread_executor.cpp +++ b/src/common/on_thread_executor.cpp @@ -16,6 +16,14 @@ std::future OnThreadExecutor::submit(task_t task) return future; } +void OnThreadExecutor::cancel() +{ + std::lock_guard lock{ _task_mutex }; + _task_queue = {}; + _task_cv.notify_one(); +} + + void OnThreadExecutor::worker_thread() { while (!_shutdown_request) diff --git a/src/common/on_thread_executor.h b/src/common/on_thread_executor.h index 2ea92c9c12..3111602f0f 100644 --- a/src/common/on_thread_executor.h +++ b/src/common/on_thread_executor.h @@ -18,6 +18,7 @@ public: OnThreadExecutor(); ~OnThreadExecutor(); std::future submit(task_t task); + void cancel(); private: void worker_thread(); diff --git a/src/modules/fancyzones/lib/ZoneWindow.cpp b/src/modules/fancyzones/lib/ZoneWindow.cpp index 8c749af4c2..141fe800cc 100644 --- a/src/modules/fancyzones/lib/ZoneWindow.cpp +++ b/src/modules/fancyzones/lib/ZoneWindow.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include +#include #include "FancyZonesData.h" #include "FancyZonesDataTypes.h" @@ -58,6 +59,56 @@ namespace ZoneWindowUtils return result; } + + void PaintZoneWindow(HDC hdc, + HWND window, + bool hasActiveZoneSet, + COLORREF hostZoneColor, + COLORREF hostZoneBorderColor, + COLORREF hostZoneHighlightColor, + int hostZoneHighlightOpacity, + std::vector> zones, + std::vector highlightZone, + bool flashMode, + bool drawHints) + { + 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) + { + ZoneWindowDrawing::DrawBackdrop(hdcMem, clientRect); + + if (hasActiveZoneSet) + { + ZoneWindowDrawing::DrawActiveZoneSet(hdcMem, + hostZoneColor, + hostZoneBorderColor, + hostZoneHighlightColor, + hostZoneHighlightOpacity, + zones, + highlightZone, + flashMode, + drawHints); + } + + EndBufferedPaint(bufferedPaint, TRUE); + } + + if (!oldHdc) + { + EndPaint(window, &ps); + } + } } struct ZoneWindow : public winrt::implements @@ -106,7 +157,7 @@ private: void CalculateZoneSet() noexcept; void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept; LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; - void OnPaint(wil::unique_hdc& hdc) noexcept; + void OnPaint(HDC hdc) noexcept; void OnKeyUp(WPARAM wparam) noexcept; std::vector ZonesFromPoint(POINT pt) noexcept; void CycleActiveZoneSetInternal(DWORD wparam, Trace::ZoneWindow::InputMode mode) noexcept; @@ -128,6 +179,8 @@ private: static const UINT m_showAnimationDuration = 200; // ms static const UINT m_flashDuration = 700; // ms + std::atomic m_animating; + OnThreadExecutor m_paintExecutor; ULONG_PTR gdiplusToken; }; @@ -143,11 +196,13 @@ ZoneWindow::ZoneWindow(HINSTANCE hinstance) 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) @@ -400,6 +455,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); @@ -407,6 +463,7 @@ ZoneWindow::ShowZoneWindow() noexcept { HideZoneWindow(); } + m_animating = false; } }.detach(); } @@ -541,23 +598,13 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept return 1; case WM_PRINTCLIENT: + { + OnPaint(reinterpret_cast(wparam)); + } + break; case WM_PAINT: { - PAINTSTRUCT ps; - wil::unique_hdc hdc{ reinterpret_cast(wparam) }; - if (!hdc) - { - hdc.reset(BeginPaint(m_window.get(), &ps)); - } - - OnPaint(hdc); - - if (wparam == 0) - { - EndPaint(m_window.get(), &ps); - } - - hdc.release(); + OnPaint(NULL); } break; @@ -569,31 +616,51 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept return 0; } -void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept +void ZoneWindow::OnPaint(HDC hdc) noexcept { - RECT clientRect; - GetClientRect(m_window.get(), &clientRect); + HWND window = m_window.get(); + bool hasActiveZoneSet = m_activeZoneSet && m_host; + COLORREF hostZoneColor{}; + COLORREF hostZoneBorderColor{}; + COLORREF hostZoneHighlightColor{}; + int hostZoneHighlightOpacity{}; + std::vector> zones{}; + std::vector highlightZone = m_highlightZone; + bool flashMode = m_flashMode; + bool drawHints = m_drawHints; - wil::unique_hdc hdcMem; - HPAINTBUFFER bufferedPaint = BeginBufferedPaint(hdc.get(), &clientRect, BPBF_TOPDOWNDIB, nullptr, &hdcMem); - if (bufferedPaint) + if (hasActiveZoneSet) { - ZoneWindowDrawing::DrawBackdrop(hdcMem, clientRect); + hostZoneColor = m_host->GetZoneColor(); + hostZoneBorderColor = m_host->GetZoneBorderColor(); + hostZoneHighlightColor = m_host->GetZoneHighlightColor(); + hostZoneHighlightOpacity = m_host->GetZoneHighlightOpacity(); + zones = m_activeZoneSet->GetZones(); + } - if (m_activeZoneSet && m_host) - { - ZoneWindowDrawing::DrawActiveZoneSet(hdcMem, - m_host->GetZoneColor(), - m_host->GetZoneBorderColor(), - m_host->GetZoneHighlightColor(), - m_host->GetZoneHighlightOpacity(), - m_activeZoneSet->GetZones(), - m_highlightZone, - m_flashMode, - m_drawHints); - } + OnThreadExecutor::task_t task{ + [=]() { + ZoneWindowUtils::PaintZoneWindow(hdc, + window, + hasActiveZoneSet, + hostZoneColor, + hostZoneBorderColor, + hostZoneHighlightColor, + hostZoneHighlightOpacity, + zones, + highlightZone, + flashMode, + drawHints); + } }; - EndBufferedPaint(bufferedPaint, TRUE); + if (m_animating) + { + task(); + } + else + { + m_paintExecutor.cancel(); + m_paintExecutor.submit(std::move(task)); } }