[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
This commit is contained in:
Ivan Stošić
2020-10-12 11:05:22 +02:00
committed by GitHub
parent 3807e98f23
commit 6161531376
3 changed files with 112 additions and 36 deletions

View File

@@ -16,6 +16,14 @@ std::future<void> 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)

View File

@@ -18,6 +18,7 @@ public:
OnThreadExecutor();
~OnThreadExecutor();
std::future<void> submit(task_t task);
void cancel();
private:
void worker_thread();

View File

@@ -1,6 +1,7 @@
#include "pch.h"
#include <common/common.h>
#include <common/on_thread_executor.h>
#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<winrt::com_ptr<IZone>> zones,
std::vector<size_t> 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<ZoneWindow, IZoneWindow>
@@ -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<size_t> 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<bool> 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<HDC>(wparam));
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
wil::unique_hdc hdc{ reinterpret_cast<HDC>(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<winrt::com_ptr<IZone>> zones{};
std::vector<size_t> 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);
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);
hostZoneColor = m_host->GetZoneColor();
hostZoneBorderColor = m_host->GetZoneBorderColor();
hostZoneHighlightColor = m_host->GetZoneHighlightColor();
hostZoneHighlightOpacity = m_host->GetZoneHighlightOpacity();
zones = m_activeZoneSet->GetZones();
}
EndBufferedPaint(bufferedPaint, TRUE);
OnThreadExecutor::task_t task{
[=]() {
ZoneWindowUtils::PaintZoneWindow(hdc,
window,
hasActiveZoneSet,
hostZoneColor,
hostZoneBorderColor,
hostZoneHighlightColor,
hostZoneHighlightOpacity,
zones,
highlightZone,
flashMode,
drawHints);
} };
if (m_animating)
{
task();
}
else
{
m_paintExecutor.cancel();
m_paintExecutor.submit(std::move(task));
}
}