[FancyZones]Fix memory leak on work area change (#31561)

* fz memleak fix

* rect comparison

* filter out unnecessary work area recreation
This commit is contained in:
Seraphima Zykova
2024-02-27 17:21:56 +01:00
committed by GitHub
parent 1f9fd2631c
commit 01a0123c3f
4 changed files with 86 additions and 34 deletions

View File

@@ -144,13 +144,14 @@ public:
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept; LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
void OnDisplayChange(DisplayChangeType changeType) noexcept; void OnDisplayChange(DisplayChangeType changeType) noexcept;
bool AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& id) noexcept; bool AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& id, const FancyZonesUtils::Rect& rect) noexcept;
protected: protected:
static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept; static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
private: private:
void UpdateWorkAreas(bool updateWindowPositions) noexcept; void UpdateWorkAreas(bool updateWindowPositions) noexcept;
bool ShouldWorkAreasBeRecreated(const std::vector<FancyZonesDataTypes::MonitorId>& monitors, const GUID& virtualDesktop, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& workAreas) noexcept;
void CycleWindows(bool reverse) noexcept; void CycleWindows(bool reverse) noexcept;
void SyncVirtualDesktops() noexcept; void SyncVirtualDesktops() noexcept;
@@ -741,7 +742,7 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
UpdateWorkAreas(updateWindowsPositions); UpdateWorkAreas(updateWindowsPositions);
} }
bool FancyZones::AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& id) noexcept bool FancyZones::AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& id, const FancyZonesUtils::Rect& rect) noexcept
{ {
auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(id.virtualDesktopId); auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(id.virtualDesktopId);
if (virtualDesktopIdStr) if (virtualDesktopIdStr)
@@ -749,16 +750,6 @@ bool FancyZones::AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAr
Logger::debug(L"Add new work area on virtual desktop {}", virtualDesktopIdStr.value()); Logger::debug(L"Add new work area on virtual desktop {}", virtualDesktopIdStr.value());
} }
FancyZonesUtils::Rect rect{};
if (monitor)
{
rect = MonitorUtils::GetWorkAreaRect(monitor);
}
else
{
rect = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
}
auto parentWorkAreaId = id; auto parentWorkAreaId = id;
parentWorkAreaId.virtualDesktopId = LastUsedVirtualDesktop::instance().GetId(); parentWorkAreaId.virtualDesktopId = LastUsedVirtualDesktop::instance().GetId();
@@ -791,27 +782,38 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept
{ {
Logger::debug(L"Update work areas, update windows positions: {}", updateWindowPositions); Logger::debug(L"Update work areas, update windows positions: {}", updateWindowPositions);
m_workAreaConfiguration.Clear();
auto currentVirtualDesktop = VirtualDesktop::instance().GetCurrentVirtualDesktopIdFromRegistry(); auto currentVirtualDesktop = VirtualDesktop::instance().GetCurrentVirtualDesktopIdFromRegistry();
if (FancyZonesSettings::settings().spanZonesAcrossMonitors) if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
{ {
std::vector<FancyZonesDataTypes::MonitorId> monitors = { FancyZonesDataTypes::MonitorId{ .monitor = nullptr, .deviceId = { .id = ZonedWindowProperties::MultiMonitorName, .instanceId = ZonedWindowProperties::MultiMonitorInstance } } };
if (ShouldWorkAreasBeRecreated(monitors, currentVirtualDesktop, m_workAreaConfiguration.GetAllWorkAreas()))
{
m_workAreaConfiguration.Clear();
FancyZonesDataTypes::WorkAreaId workAreaId; FancyZonesDataTypes::WorkAreaId workAreaId;
workAreaId.virtualDesktopId = currentVirtualDesktop; workAreaId.virtualDesktopId = currentVirtualDesktop;
workAreaId.monitorId = { .deviceId = { .id = ZonedWindowProperties::MultiMonitorName, .instanceId = ZonedWindowProperties::MultiMonitorInstance } }; workAreaId.monitorId = { .deviceId = { .id = ZonedWindowProperties::MultiMonitorName, .instanceId = ZonedWindowProperties::MultiMonitorInstance } };
AddWorkArea(nullptr, workAreaId); AddWorkArea(nullptr, workAreaId, FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>());
}
} }
else else
{ {
auto monitors = MonitorUtils::IdentifyMonitors(); auto monitors = MonitorUtils::IdentifyMonitors();
const auto& workAreas = m_workAreaConfiguration.GetAllWorkAreas();
if (ShouldWorkAreasBeRecreated(monitors, currentVirtualDesktop, workAreas))
{
m_workAreaConfiguration.Clear();
for (const auto& monitor : monitors) for (const auto& monitor : monitors)
{ {
FancyZonesDataTypes::WorkAreaId workAreaId; FancyZonesDataTypes::WorkAreaId workAreaId;
workAreaId.virtualDesktopId = currentVirtualDesktop; workAreaId.virtualDesktopId = currentVirtualDesktop;
workAreaId.monitorId = monitor; workAreaId.monitorId = monitor;
AddWorkArea(monitor.monitor, workAreaId); AddWorkArea(monitor.monitor, workAreaId, MonitorUtils::GetWorkAreaRect(monitor.monitor));
}
} }
} }
@@ -885,6 +887,52 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept
} }
} }
bool FancyZones::ShouldWorkAreasBeRecreated(const std::vector<FancyZonesDataTypes::MonitorId>& monitors, const GUID& virtualDesktop, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& workAreas) noexcept
{
if (monitors.size() != workAreas.size())
{
Logger::trace(L"Monitor was added or removed");
return true;
}
for (const auto& monitor : monitors)
{
auto iter = workAreas.find(monitor.monitor);
if (iter == workAreas.end())
{
Logger::trace(L"WorkArea not found");
return true;
}
if (iter->second->UniqueId().monitorId.deviceId != monitor.deviceId)
{
Logger::trace(L"DeviceId changed");
return true;
}
if (iter->second->UniqueId().monitorId.serialNumber != monitor.serialNumber)
{
Logger::trace(L"Serial number changed");
return true;
}
if (iter->second->UniqueId().virtualDesktopId != virtualDesktop)
{
Logger::trace(L"Virtual desktop changed");
return true;
}
const auto rect = monitor.monitor ? MonitorUtils::GetWorkAreaRect(monitor.monitor) : FancyZonesUtils::Rect(FancyZonesUtils::GetMonitorsCombinedRect<&MONITORINFOEX::rcWork>(FancyZonesUtils::GetAllMonitorRects<&MONITORINFOEX::rcWork>()));
if (iter->second->GetWorkAreaRect() != rect)
{
Logger::trace(L"WorkArea size changed");
return true;
}
}
return false;
}
void FancyZones::CycleWindows(bool reverse) noexcept void FancyZones::CycleWindows(bool reverse) noexcept
{ {
auto window = GetForegroundWindow(); auto window = GetForegroundWindow();

View File

@@ -41,16 +41,6 @@ float ZonesOverlay::GetAnimationAlpha()
return std::clamp(millis / FadeInDurationMillis, 0.001f, 1.f); return std::clamp(millis / FadeInDurationMillis, 0.001f, 1.f);
} }
ID2D1Factory* ZonesOverlay::GetD2DFactory()
{
static auto pD2DFactory = [] {
ID2D1Factory* res = nullptr;
D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &res);
return res;
}();
return pD2DFactory;
}
IDWriteFactory* ZonesOverlay::GetWriteFactory() IDWriteFactory* ZonesOverlay::GetWriteFactory()
{ {
static auto pDWriteFactory = [] { static auto pDWriteFactory = [] {
@@ -99,7 +89,11 @@ ZonesOverlay::ZonesOverlay(HWND window)
auto renderTargetSize = D2D1::SizeU(m_clientRect.right - m_clientRect.left, m_clientRect.bottom - m_clientRect.top); auto renderTargetSize = D2D1::SizeU(m_clientRect.right - m_clientRect.left, m_clientRect.bottom - m_clientRect.top);
auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(window, renderTargetSize); auto hwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(window, renderTargetSize);
hr = GetD2DFactory()->CreateHwndRenderTarget(renderTargetProperties, hwndRenderTargetProperties, &m_renderTarget); ID2D1Factory* factory = nullptr;
D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &factory);
hr = factory->CreateHwndRenderTarget(renderTargetProperties, hwndRenderTargetProperties, &m_renderTarget);
factory->Release();
factory = nullptr;
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
{ {
@@ -357,5 +351,6 @@ ZonesOverlay::~ZonesOverlay()
if (m_renderTarget) if (m_renderTarget)
{ {
m_renderTarget->Release(); m_renderTarget->Release();
m_renderTarget = nullptr;
} }
} }

View File

@@ -47,7 +47,6 @@ class ZonesOverlay
std::vector<DrawableRect> m_sceneRects; std::vector<DrawableRect> m_sceneRects;
float GetAnimationAlpha(); float GetAnimationAlpha();
static ID2D1Factory* GetD2DFactory();
static IDWriteFactory* GetWriteFactory(); static IDWriteFactory* GetWriteFactory();
static D2D1_COLOR_F ConvertColor(COLORREF color); static D2D1_COLOR_F ConvertColor(COLORREF color);
static D2D1_RECT_F ConvertRect(RECT rect); static D2D1_RECT_F ConvertRect(RECT rect);

View File

@@ -34,6 +34,16 @@ namespace FancyZonesUtils
RECT m_rect{}; RECT m_rect{};
}; };
inline bool operator==(const FancyZonesUtils::Rect& left, const FancyZonesUtils::Rect& right)
{
return left.left() == right.left() && left.right() == right.right() && left.top() == right.top() && left.bottom() == right.bottom();
}
inline bool operator!=(const FancyZonesUtils::Rect& left, const FancyZonesUtils::Rect& right)
{
return left.left() != right.left() || left.right() != right.right() || left.top() != right.top() || left.bottom() != right.bottom();
}
inline void InitRGB(_Out_ RGBQUAD* quad, BYTE alpha, COLORREF color) inline void InitRGB(_Out_ RGBQUAD* quad, BYTE alpha, COLORREF color)
{ {
ZeroMemory(quad, sizeof(*quad)); ZeroMemory(quad, sizeof(*quad));