mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-12-13 19:19:23 +08:00
[FancyZones] Use a window pool for zone windows (#9625)
* Implemented and tested WindowPool * Added mutex * Add logs to WindowPool * Fix a potential thread safety bug
This commit is contained in:
parent
e586a7ad64
commit
72da703f0e
@ -25,6 +25,81 @@ namespace NonLocalizable
|
|||||||
|
|
||||||
using namespace FancyZonesUtils;
|
using namespace FancyZonesUtils;
|
||||||
|
|
||||||
|
struct ZoneWindow;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// The reason for using this class is the need to call ShowWindow(window, SW_SHOWNORMAL); on each
|
||||||
|
// newly created window for it to be displayed properly. The call sometimes has side effects when
|
||||||
|
// a fullscreen app is running, and happens when the resolution change event is triggered
|
||||||
|
// (e.g. when running some games).
|
||||||
|
// This class will serve as a pool of windows for which this call was already done.
|
||||||
|
class WindowPool
|
||||||
|
{
|
||||||
|
std::vector<HWND> m_pool;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
|
||||||
|
HWND ExtractWindow()
|
||||||
|
{
|
||||||
|
std::unique_lock lock(m_mutex);
|
||||||
|
|
||||||
|
if (m_pool.empty())
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND window = m_pool.back();
|
||||||
|
m_pool.pop_back();
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HWND NewZoneWindow(Rect position, HINSTANCE hinstance, ZoneWindow* owner)
|
||||||
|
{
|
||||||
|
HWND windowFromPool = ExtractWindow();
|
||||||
|
if (windowFromPool == NULL)
|
||||||
|
{
|
||||||
|
HWND window = CreateWindowExW(WS_EX_TOOLWINDOW, NonLocalizable::ToolWindowClassName, L"", WS_POPUP, position.left(), position.top(), position.width(), position.height(), nullptr, nullptr, hinstance, owner);
|
||||||
|
Logger::info("Creating new zone window, hWnd = {}", (void*)window);
|
||||||
|
MakeWindowTransparent(window);
|
||||||
|
|
||||||
|
// According to ShowWindow docs, we must call it with SW_SHOWNORMAL the first time
|
||||||
|
ShowWindow(window, SW_SHOWNORMAL);
|
||||||
|
ShowWindow(window, SW_HIDE);
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::info("Reusing zone window from pool, hWnd = {}", (void*)windowFromPool);
|
||||||
|
SetWindowLongPtrW(windowFromPool, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(owner));
|
||||||
|
MoveWindow(windowFromPool, position.left(), position.top(), position.width(), position.height(), TRUE);
|
||||||
|
return windowFromPool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeZoneWindow(HWND window)
|
||||||
|
{
|
||||||
|
Logger::info("Freeing zone window, hWnd = {}", (void*)window);
|
||||||
|
SetWindowLongPtrW(window, GWLP_USERDATA, 0);
|
||||||
|
ShowWindow(window, SW_HIDE);
|
||||||
|
|
||||||
|
std::unique_lock lock(m_mutex);
|
||||||
|
m_pool.push_back(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
~WindowPool()
|
||||||
|
{
|
||||||
|
for (HWND window : m_pool)
|
||||||
|
{
|
||||||
|
DestroyWindow(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WindowPool windowPool;
|
||||||
|
}
|
||||||
|
|
||||||
struct ZoneWindow : public winrt::implements<ZoneWindow, IZoneWindow>
|
struct ZoneWindow : public winrt::implements<ZoneWindow, IZoneWindow>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -78,7 +153,7 @@ private:
|
|||||||
winrt::com_ptr<IZoneWindowHost> m_host;
|
winrt::com_ptr<IZoneWindowHost> m_host;
|
||||||
HMONITOR m_monitor{};
|
HMONITOR m_monitor{};
|
||||||
std::wstring m_uniqueId; // Parsed deviceId + resolution + virtualDesktopId
|
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_window{}; // Hidden tool window used to represent current monitor desktop work area.
|
||||||
HWND m_windowMoveSize{};
|
HWND m_windowMoveSize{};
|
||||||
winrt::com_ptr<IZoneSet> m_activeZoneSet;
|
winrt::com_ptr<IZoneSet> m_activeZoneSet;
|
||||||
std::vector<winrt::com_ptr<IZoneSet>> m_zoneSets;
|
std::vector<winrt::com_ptr<IZoneSet>> m_zoneSets;
|
||||||
@ -104,6 +179,7 @@ ZoneWindow::ZoneWindow(HINSTANCE hinstance)
|
|||||||
|
|
||||||
ZoneWindow::~ZoneWindow()
|
ZoneWindow::~ZoneWindow()
|
||||||
{
|
{
|
||||||
|
windowPool.FreeZoneWindow(m_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId)
|
bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monitor, const std::wstring& uniqueId, const std::wstring& parentUniqueId)
|
||||||
@ -130,21 +206,14 @@ bool ZoneWindow::Init(IZoneWindowHost* host, HINSTANCE hinstance, HMONITOR monit
|
|||||||
m_uniqueId = uniqueId;
|
m_uniqueId = uniqueId;
|
||||||
InitializeZoneSets(parentUniqueId);
|
InitializeZoneSets(parentUniqueId);
|
||||||
|
|
||||||
m_window = wil::unique_hwnd{
|
m_window = windowPool.NewZoneWindow(workAreaRect, hinstance, this);
|
||||||
CreateWindowExW(WS_EX_TOOLWINDOW, NonLocalizable::ToolWindowClassName, L"", WS_POPUP, workAreaRect.left(), workAreaRect.top(), workAreaRect.width(), workAreaRect.height(), nullptr, nullptr, hinstance, this)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!m_window)
|
if (!m_window)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MakeWindowTransparent(m_window.get());
|
m_zoneWindowDrawing = std::make_unique<ZoneWindowDrawing>(m_window);
|
||||||
// According to ShowWindow docs, we must call it with SW_SHOWNORMAL the first time
|
|
||||||
ShowWindow(m_window.get(), SW_SHOWNORMAL);
|
|
||||||
ShowWindow(m_window.get(), SW_HIDE);
|
|
||||||
|
|
||||||
m_zoneWindowDrawing = std::make_unique<ZoneWindowDrawing>(m_window.get());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -162,7 +231,7 @@ IFACEMETHODIMP ZoneWindow::MoveSizeUpdate(POINT const& ptScreen, bool dragEnable
|
|||||||
{
|
{
|
||||||
bool redraw = false;
|
bool redraw = false;
|
||||||
POINT ptClient = ptScreen;
|
POINT ptClient = ptScreen;
|
||||||
MapWindowPoints(nullptr, m_window.get(), &ptClient, 1);
|
MapWindowPoints(nullptr, m_window, &ptClient, 1);
|
||||||
|
|
||||||
if (dragEnabled)
|
if (dragEnabled)
|
||||||
{
|
{
|
||||||
@ -212,8 +281,8 @@ IFACEMETHODIMP ZoneWindow::MoveSizeEnd(HWND window, POINT const& ptScreen) noexc
|
|||||||
if (m_activeZoneSet)
|
if (m_activeZoneSet)
|
||||||
{
|
{
|
||||||
POINT ptClient = ptScreen;
|
POINT ptClient = ptScreen;
|
||||||
MapWindowPoints(nullptr, m_window.get(), &ptClient, 1);
|
MapWindowPoints(nullptr, m_window, &ptClient, 1);
|
||||||
m_activeZoneSet->MoveWindowIntoZoneByIndexSet(window, m_window.get(), m_highlightZone);
|
m_activeZoneSet->MoveWindowIntoZoneByIndexSet(window, m_window, m_highlightZone);
|
||||||
|
|
||||||
if (FancyZonesUtils::HasNoVisibleOwner(window))
|
if (FancyZonesUtils::HasNoVisibleOwner(window))
|
||||||
{
|
{
|
||||||
@ -238,7 +307,7 @@ ZoneWindow::MoveWindowIntoZoneByIndexSet(HWND window, const std::vector<size_t>&
|
|||||||
{
|
{
|
||||||
if (m_activeZoneSet)
|
if (m_activeZoneSet)
|
||||||
{
|
{
|
||||||
m_activeZoneSet->MoveWindowIntoZoneByIndexSet(window, m_window.get(), indexSet);
|
m_activeZoneSet->MoveWindowIntoZoneByIndexSet(window, m_window, indexSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +316,7 @@ ZoneWindow::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, boo
|
|||||||
{
|
{
|
||||||
if (m_activeZoneSet)
|
if (m_activeZoneSet)
|
||||||
{
|
{
|
||||||
if (m_activeZoneSet->MoveWindowIntoZoneByDirectionAndIndex(window, m_window.get(), vkCode, cycle))
|
if (m_activeZoneSet->MoveWindowIntoZoneByDirectionAndIndex(window, m_window, vkCode, cycle))
|
||||||
{
|
{
|
||||||
if (FancyZonesUtils::HasNoVisibleOwner(window))
|
if (FancyZonesUtils::HasNoVisibleOwner(window))
|
||||||
{
|
{
|
||||||
@ -264,7 +333,7 @@ ZoneWindow::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode,
|
|||||||
{
|
{
|
||||||
if (m_activeZoneSet)
|
if (m_activeZoneSet)
|
||||||
{
|
{
|
||||||
if (m_activeZoneSet->MoveWindowIntoZoneByDirectionAndPosition(window, m_window.get(), vkCode, cycle))
|
if (m_activeZoneSet->MoveWindowIntoZoneByDirectionAndPosition(window, m_window, vkCode, cycle))
|
||||||
{
|
{
|
||||||
SaveWindowProcessToZoneIndex(window);
|
SaveWindowProcessToZoneIndex(window);
|
||||||
return true;
|
return true;
|
||||||
@ -278,7 +347,7 @@ ZoneWindow::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexce
|
|||||||
{
|
{
|
||||||
if (m_activeZoneSet)
|
if (m_activeZoneSet)
|
||||||
{
|
{
|
||||||
if (m_activeZoneSet->ExtendWindowByDirectionAndPosition(window, m_window.get(), vkCode))
|
if (m_activeZoneSet->ExtendWindowByDirectionAndPosition(window, m_window, vkCode))
|
||||||
{
|
{
|
||||||
SaveWindowProcessToZoneIndex(window);
|
SaveWindowProcessToZoneIndex(window);
|
||||||
return true;
|
return true;
|
||||||
@ -294,7 +363,7 @@ ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept
|
|||||||
|
|
||||||
if (m_windowMoveSize)
|
if (m_windowMoveSize)
|
||||||
{
|
{
|
||||||
InvalidateRect(m_window.get(), nullptr, true);
|
InvalidateRect(m_window, nullptr, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +389,7 @@ ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
|
|||||||
IFACEMETHODIMP_(void)
|
IFACEMETHODIMP_(void)
|
||||||
ZoneWindow::ShowZoneWindow() noexcept
|
ZoneWindow::ShowZoneWindow() noexcept
|
||||||
{
|
{
|
||||||
auto window = m_window.get();
|
auto window = m_window;
|
||||||
if (!window)
|
if (!window)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -461,8 +530,8 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
|||||||
{
|
{
|
||||||
case WM_NCDESTROY:
|
case WM_NCDESTROY:
|
||||||
{
|
{
|
||||||
::DefWindowProc(m_window.get(), message, wparam, lparam);
|
::DefWindowProc(m_window, message, wparam, lparam);
|
||||||
SetWindowLongPtr(m_window.get(), GWLP_USERDATA, 0);
|
SetWindowLongPtr(m_window, GWLP_USERDATA, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -477,7 +546,7 @@ LRESULT ZoneWindow::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
return DefWindowProc(m_window.get(), message, wparam, lparam);
|
return DefWindowProc(m_window, message, wparam, lparam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user