Thread safety for FanncyZonesData (#1281)

* FancyZones: make FancyZonesData thread-safe

* fixup: format affected sources

* fixup: clang-format case-style and format FancyZones.cpp

* fixup! add missing lock
This commit is contained in:
Andrey Nekrasov
2020-02-17 18:28:49 +03:00
committed by GitHub
parent cdf2f6b5b4
commit 1e6936a8c3
10 changed files with 1631 additions and 1533 deletions

View File

@@ -20,6 +20,7 @@ AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false BinPackArguments: false
BinPackParameters: false BinPackParameters: false
BraceWrapping: BraceWrapping:
AfterCaseLabel: true
AfterClass: true AfterClass: true
AfterControlStatement: true AfterControlStatement: true
AfterEnum: true AfterEnum: true
@@ -28,7 +29,7 @@ BraceWrapping:
AfterObjCDeclaration: true AfterObjCDeclaration: true
AfterStruct: true AfterStruct: true
AfterUnion: true AfterUnion: true
AfterExternBlock: false AfterExternBlock: true
BeforeCatch: true BeforeCatch: true
BeforeElse: true BeforeElse: true
IndentBraces: false IndentBraces: false
@@ -90,4 +91,4 @@ SpacesInParentheses: false
SpacesInSquareBrackets: false SpacesInSquareBrackets: false
Standard: Cpp11 Standard: Cpp11
TabWidth: 4 TabWidth: 4
UseTab: Never UseTab: Never

View File

@@ -47,28 +47,42 @@ public:
} }
// IFancyZones // IFancyZones
IFACEMETHODIMP_(void) Run() noexcept; IFACEMETHODIMP_(void)
IFACEMETHODIMP_(void) Destroy() noexcept; Run() noexcept;
IFACEMETHODIMP_(void)
Destroy() noexcept;
// IFancyZonesCallback // IFancyZonesCallback
IFACEMETHODIMP_(bool) InMoveSize() noexcept IFACEMETHODIMP_(bool)
InMoveSize() noexcept
{ {
std::shared_lock readLock(m_lock); std::shared_lock readLock(m_lock);
return m_inMoveSize; return m_inMoveSize;
} }
IFACEMETHODIMP_(void) MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept; IFACEMETHODIMP_(void)
IFACEMETHODIMP_(void) MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept; MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept;
IFACEMETHODIMP_(void) MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept; IFACEMETHODIMP_(void)
IFACEMETHODIMP_(void) VirtualDesktopChanged() noexcept; MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept;
IFACEMETHODIMP_(void) VirtualDesktopInitialize() noexcept; IFACEMETHODIMP_(void)
IFACEMETHODIMP_(void) WindowCreated(HWND window) noexcept; MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept;
IFACEMETHODIMP_(bool) OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept; IFACEMETHODIMP_(void)
IFACEMETHODIMP_(void) ToggleEditor() noexcept; VirtualDesktopChanged() noexcept;
IFACEMETHODIMP_(void) SettingsChanged() noexcept; IFACEMETHODIMP_(void)
VirtualDesktopInitialize() noexcept;
IFACEMETHODIMP_(void)
WindowCreated(HWND window) noexcept;
IFACEMETHODIMP_(bool)
OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept;
IFACEMETHODIMP_(void)
ToggleEditor() noexcept;
IFACEMETHODIMP_(void)
SettingsChanged() noexcept;
// IZoneWindowHost // IZoneWindowHost
IFACEMETHODIMP_(void) MoveWindowsOnActiveZoneSetChange() noexcept; IFACEMETHODIMP_(void)
IFACEMETHODIMP_(COLORREF) GetZoneHighlightColor() noexcept MoveWindowsOnActiveZoneSetChange() noexcept;
IFACEMETHODIMP_(COLORREF)
GetZoneHighlightColor() noexcept
{ {
// Skip the leading # and convert to long // Skip the leading # and convert to long
const auto color = m_settings->GetSettings().zoneHightlightColor; const auto color = m_settings->GetSettings().zoneHightlightColor;
@@ -78,7 +92,8 @@ public:
const auto nB = (tmp & 0xFF); const auto nB = (tmp & 0xFF);
return RGB(nR, nG, nB); return RGB(nR, nG, nB);
} }
IFACEMETHODIMP_(IZoneWindow*)GetParentZoneWindow(HMONITOR monitor) noexcept IFACEMETHODIMP_(IZoneWindow*)
GetParentZoneWindow(HMONITOR monitor) noexcept
{ {
//NOTE: as public method it's unsafe without lock, but it's called from AddZoneWindow through making ZoneWindow that causes deadlock //NOTE: as public method it's unsafe without lock, but it's called from AddZoneWindow through making ZoneWindow that causes deadlock
//TODO: needs refactoring //TODO: needs refactoring
@@ -89,7 +104,8 @@ public:
} }
return nullptr; return nullptr;
} }
IFACEMETHODIMP_(int) GetZoneHighlightOpacity() noexcept IFACEMETHODIMP_(int)
GetZoneHighlightOpacity() noexcept
{ {
return m_settings->GetSettings().zoneHighlightOpacity; return m_settings->GetSettings().zoneHighlightOpacity;
} }
@@ -176,7 +192,8 @@ UINT FancyZones::WM_PRIV_VDINIT = RegisterWindowMessage(L"{469818a8-00fa-4069-b8
UINT FancyZones::WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}"); UINT FancyZones::WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}");
// IFancyZones // IFancyZones
IFACEMETHODIMP_(void) FancyZones::Run() noexcept IFACEMETHODIMP_(void)
FancyZones::Run() noexcept
{ {
std::unique_lock writeLock(m_lock); std::unique_lock writeLock(m_lock);
@@ -212,7 +229,8 @@ IFACEMETHODIMP_(void) FancyZones::Run() noexcept
} }
// IFancyZones // IFancyZones
IFACEMETHODIMP_(void) FancyZones::Destroy() noexcept IFACEMETHODIMP_(void)
FancyZones::Destroy() noexcept
{ {
std::unique_lock writeLock(m_lock); std::unique_lock writeLock(m_lock);
m_zoneWindowMap.clear(); m_zoneWindowMap.clear();
@@ -234,7 +252,8 @@ IFACEMETHODIMP_(void) FancyZones::Destroy() noexcept
} }
// IFancyZonesCallback // IFancyZonesCallback
IFACEMETHODIMP_(void) FancyZones::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept IFACEMETHODIMP_(void)
FancyZones::MoveSizeStart(HWND window, HMONITOR monitor, POINT const& ptScreen) noexcept
{ {
if (IsInterestingWindow(window)) if (IsInterestingWindow(window))
{ {
@@ -244,14 +263,16 @@ IFACEMETHODIMP_(void) FancyZones::MoveSizeStart(HWND window, HMONITOR monitor, P
} }
// IFancyZonesCallback // IFancyZonesCallback
IFACEMETHODIMP_(void) FancyZones::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept IFACEMETHODIMP_(void)
FancyZones::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen) noexcept
{ {
std::unique_lock writeLock(m_lock); std::unique_lock writeLock(m_lock);
MoveSizeUpdateInternal(monitor, ptScreen, writeLock); MoveSizeUpdateInternal(monitor, ptScreen, writeLock);
} }
// IFancyZonesCallback // IFancyZonesCallback
IFACEMETHODIMP_(void) FancyZones::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept IFACEMETHODIMP_(void)
FancyZones::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
{ {
if (window == m_windowMoveSize || IsInterestingWindow(window)) if (window == m_windowMoveSize || IsInterestingWindow(window))
{ {
@@ -261,7 +282,8 @@ IFACEMETHODIMP_(void) FancyZones::MoveSizeEnd(HWND window, POINT const& ptScreen
} }
// IFancyZonesCallback // IFancyZonesCallback
IFACEMETHODIMP_(void) FancyZones::VirtualDesktopChanged() noexcept IFACEMETHODIMP_(void)
FancyZones::VirtualDesktopChanged() noexcept
{ {
// VirtualDesktopChanged is called from another thread but results in new windows being created. // VirtualDesktopChanged is called from another thread but results in new windows being created.
// Jump over to the UI thread to handle it. // Jump over to the UI thread to handle it.
@@ -270,13 +292,15 @@ IFACEMETHODIMP_(void) FancyZones::VirtualDesktopChanged() noexcept
} }
// IFancyZonesCallback // IFancyZonesCallback
IFACEMETHODIMP_(void) FancyZones::VirtualDesktopInitialize() noexcept IFACEMETHODIMP_(void)
FancyZones::VirtualDesktopInitialize() noexcept
{ {
PostMessage(m_window, WM_PRIV_VDINIT, 0, 0); PostMessage(m_window, WM_PRIV_VDINIT, 0, 0);
} }
// IFancyZonesCallback // IFancyZonesCallback
IFACEMETHODIMP_(void) FancyZones::WindowCreated(HWND window) noexcept IFACEMETHODIMP_(void)
FancyZones::WindowCreated(HWND window) noexcept
{ {
if (m_settings->GetSettings().appLastZone_moveWindows && IsInterestingWindow(window)) if (m_settings->GetSettings().appLastZone_moveWindows && IsInterestingWindow(window))
{ {
@@ -308,7 +332,8 @@ IFACEMETHODIMP_(void) FancyZones::WindowCreated(HWND window) noexcept
} }
// IFancyZonesCallback // IFancyZonesCallback
IFACEMETHODIMP_(bool) FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept IFACEMETHODIMP_(bool)
FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
{ {
// Return true to swallow the keyboard event // Return true to swallow the keyboard event
bool const shift = GetAsyncKeyState(VK_SHIFT) & 0x8000; bool const shift = GetAsyncKeyState(VK_SHIFT) & 0x8000;
@@ -430,9 +455,13 @@ void FancyZones::ToggleEditor() noexcept
std::to_wstring(width) + L"_" + std::to_wstring(width) + L"_" +
std::to_wstring(height); std::to_wstring(height);
const auto& deviceInfo = fancyZonesData.GetDeviceInfoMap().at(zoneWindow->UniqueId()); const auto deviceInfo = fancyZonesData.FindDeviceInfo(zoneWindow->UniqueId());
if (!deviceInfo.has_value())
{
return;
}
JSONHelpers::DeviceInfoJSON deviceInfoJson{ zoneWindow->UniqueId(), deviceInfo }; JSONHelpers::DeviceInfoJSON deviceInfoJson{ zoneWindow->UniqueId(), *deviceInfo };
fancyZonesData.SerializeDeviceInfoToTmpFile(deviceInfoJson, ZoneWindowUtils::GetActiveZoneSetTmpPath()); fancyZonesData.SerializeDeviceInfoToTmpFile(deviceInfoJson, ZoneWindowUtils::GetActiveZoneSetTmpPath());
const std::wstring params = const std::wstring params =
@@ -484,7 +513,8 @@ void FancyZones::SettingsChanged() noexcept
} }
// IZoneWindowHost // IZoneWindowHost
IFACEMETHODIMP_(void) FancyZones::MoveWindowsOnActiveZoneSetChange() noexcept IFACEMETHODIMP_(void)
FancyZones::MoveWindowsOnActiveZoneSetChange() noexcept
{ {
if (m_settings->GetSettings().zoneSetChange_moveWindows) if (m_settings->GetSettings().zoneSetChange_moveWindows)
{ {
@@ -566,7 +596,7 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
GUID currentVirtualDesktopId{}; GUID currentVirtualDesktopId{};
if (SUCCEEDED(RegistryHelpers::GetCurrentVirtualDesktop(&currentVirtualDesktopId))) if (SUCCEEDED(RegistryHelpers::GetCurrentVirtualDesktop(&currentVirtualDesktopId)))
{ {
std::unique_lock writeLock(m_lock); std::unique_lock writeLock(m_lock);
m_currentVirtualDesktopId = currentVirtualDesktopId; m_currentVirtualDesktopId = currentVirtualDesktopId;
} }
else else

View File

@@ -135,13 +135,10 @@ namespace JSONHelpers
jsonFilePath = result + L"\\" + std::wstring(FANCY_ZONES_DATA_FILE); jsonFilePath = result + L"\\" + std::wstring(FANCY_ZONES_DATA_FILE);
} }
const std::wstring& FancyZonesData::GetPersistFancyZonesJSONPath() const
{
return jsonFilePath;
}
json::JsonObject FancyZonesData::GetPersistFancyZonesJSON() json::JsonObject FancyZonesData::GetPersistFancyZonesJSON()
{ {
std::scoped_lock lock{ dataLock };
std::wstring save_file_path = GetPersistFancyZonesJSONPath(); std::wstring save_file_path = GetPersistFancyZonesJSONPath();
auto result = json::from_file(save_file_path); auto result = json::from_file(save_file_path);
@@ -155,12 +152,27 @@ namespace JSONHelpers
} }
} }
std::optional<DeviceInfoData> FancyZonesData::FindDeviceInfo(const std::wstring& zoneWindowId) const
{
std::scoped_lock lock{ dataLock };
auto it = deviceInfoMap.find(zoneWindowId);
return it != end(deviceInfoMap) ? std::optional{ it->second } : std::nullopt;
}
std::optional<CustomZoneSetData> FancyZonesData::FindCustomZoneSet(const std::wstring& guuid) const
{
std::scoped_lock lock{ dataLock };
auto it = customZoneSetsMap.find(guuid);
return it != end(customZoneSetsMap) ? std::optional{ it->second } : std::nullopt;
}
void FancyZonesData::AddDevice(const std::wstring& deviceId) void FancyZonesData::AddDevice(const std::wstring& deviceId)
{ {
std::scoped_lock lock{ dataLock };
if (!deviceInfoMap.contains(deviceId)) if (!deviceInfoMap.contains(deviceId))
{ {
// Creates default entry in map when ZoneWindow is created // Creates default entry in map when ZoneWindow is created
deviceInfoMap[deviceId] = DeviceInfoData{ ZoneSetData{ L"null", ZoneSetLayoutType::Blank } }; deviceInfoMap[deviceId] = DeviceInfoData{ ZoneSetData{ L"null", ZoneSetLayoutType::Blank } };
MigrateDeviceInfoFromRegistry(deviceId); MigrateDeviceInfoFromRegistry(deviceId);
} }
@@ -168,6 +180,7 @@ namespace JSONHelpers
void FancyZonesData::CloneDeviceInfo(const std::wstring& source, const std::wstring& destination) void FancyZonesData::CloneDeviceInfo(const std::wstring& source, const std::wstring& destination)
{ {
std::scoped_lock lock{ dataLock };
// Clone information from source device if destination device is uninitialized (Blank). // Clone information from source device if destination device is uninitialized (Blank).
auto& destInfo = deviceInfoMap[destination]; auto& destInfo = deviceInfoMap[destination];
if (destInfo.activeZoneSet.type == ZoneSetLayoutType::Blank) if (destInfo.activeZoneSet.type == ZoneSetLayoutType::Blank)
@@ -178,6 +191,7 @@ namespace JSONHelpers
int FancyZonesData::GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const int FancyZonesData::GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const
{ {
std::scoped_lock lock{ dataLock };
auto processPath = get_process_path(window); auto processPath = get_process_path(window);
if (!processPath.empty()) if (!processPath.empty())
{ {
@@ -188,7 +202,7 @@ namespace JSONHelpers
if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId) if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId)
{ {
return history->second.zoneIndex; return history->second.zoneIndex;
} }
} }
} }
@@ -197,6 +211,7 @@ namespace JSONHelpers
bool FancyZonesData::RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) bool FancyZonesData::RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId)
{ {
std::scoped_lock lock{ dataLock };
auto processPath = get_process_path(window); auto processPath = get_process_path(window);
if (!processPath.empty()) if (!processPath.empty())
{ {
@@ -218,6 +233,7 @@ namespace JSONHelpers
bool FancyZonesData::SetAppLastZone(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, int zoneIndex) bool FancyZonesData::SetAppLastZone(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, int zoneIndex)
{ {
std::scoped_lock lock{ dataLock };
auto processPath = get_process_path(window); auto processPath = get_process_path(window);
if (processPath.empty()) if (processPath.empty())
{ {
@@ -231,6 +247,7 @@ namespace JSONHelpers
void FancyZonesData::SetActiveZoneSet(const std::wstring& deviceId, const ZoneSetData& data) void FancyZonesData::SetActiveZoneSet(const std::wstring& deviceId, const ZoneSetData& data)
{ {
std::scoped_lock lock{ dataLock };
auto it = deviceInfoMap.find(deviceId); auto it = deviceInfoMap.find(deviceId);
if (it != deviceInfoMap.end()) if (it != deviceInfoMap.end())
{ {
@@ -240,12 +257,14 @@ namespace JSONHelpers
void FancyZonesData::SerializeDeviceInfoToTmpFile(const DeviceInfoJSON& deviceInfo, std::wstring_view tmpFilePath) const void FancyZonesData::SerializeDeviceInfoToTmpFile(const DeviceInfoJSON& deviceInfo, std::wstring_view tmpFilePath) const
{ {
std::scoped_lock lock{ dataLock };
json::JsonObject deviceInfoJson = DeviceInfoJSON::ToJson(deviceInfo); json::JsonObject deviceInfoJson = DeviceInfoJSON::ToJson(deviceInfo);
json::to_file(tmpFilePath, deviceInfoJson); json::to_file(tmpFilePath, deviceInfoJson);
} }
void FancyZonesData::ParseDeviceInfoFromTmpFile(std::wstring_view tmpFilePath) void FancyZonesData::ParseDeviceInfoFromTmpFile(std::wstring_view tmpFilePath)
{ {
std::scoped_lock lock{ dataLock };
if (std::filesystem::exists(tmpFilePath)) if (std::filesystem::exists(tmpFilePath))
{ {
if (auto zoneSetJson = json::from_file(tmpFilePath); zoneSetJson.has_value()) if (auto zoneSetJson = json::from_file(tmpFilePath); zoneSetJson.has_value())
@@ -266,6 +285,7 @@ namespace JSONHelpers
bool FancyZonesData::ParseCustomZoneSetFromTmpFile(std::wstring_view tmpFilePath) bool FancyZonesData::ParseCustomZoneSetFromTmpFile(std::wstring_view tmpFilePath)
{ {
std::scoped_lock lock{ dataLock };
bool res = true; bool res = true;
if (std::filesystem::exists(tmpFilePath)) if (std::filesystem::exists(tmpFilePath))
{ {
@@ -291,6 +311,7 @@ namespace JSONHelpers
bool FancyZonesData::ParseDeletedCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath) bool FancyZonesData::ParseDeletedCustomZoneSetsFromTmpFile(std::wstring_view tmpFilePath)
{ {
std::scoped_lock lock{ dataLock };
bool res = true; bool res = true;
if (std::filesystem::exists(tmpFilePath)) if (std::filesystem::exists(tmpFilePath))
{ {
@@ -317,6 +338,7 @@ namespace JSONHelpers
bool FancyZonesData::ParseAppZoneHistory(const json::JsonObject& fancyZonesDataJSON) bool FancyZonesData::ParseAppZoneHistory(const json::JsonObject& fancyZonesDataJSON)
{ {
std::scoped_lock lock{ dataLock };
try try
{ {
auto appLastZones = fancyZonesDataJSON.GetNamedArray(L"app-zone-history"); auto appLastZones = fancyZonesDataJSON.GetNamedArray(L"app-zone-history");
@@ -344,6 +366,7 @@ namespace JSONHelpers
json::JsonArray FancyZonesData::SerializeAppZoneHistory() const json::JsonArray FancyZonesData::SerializeAppZoneHistory() const
{ {
std::scoped_lock lock{ dataLock };
json::JsonArray appHistoryArray; json::JsonArray appHistoryArray;
for (const auto& [appPath, appZoneHistoryData] : appZoneHistoryMap) for (const auto& [appPath, appZoneHistoryData] : appZoneHistoryMap)
@@ -356,6 +379,7 @@ namespace JSONHelpers
bool FancyZonesData::ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON) bool FancyZonesData::ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON)
{ {
std::scoped_lock lock{ dataLock };
try try
{ {
auto devices = fancyZonesDataJSON.GetNamedArray(L"devices"); auto devices = fancyZonesDataJSON.GetNamedArray(L"devices");
@@ -382,11 +406,13 @@ namespace JSONHelpers
json::JsonArray FancyZonesData::SerializeDeviceInfos() const json::JsonArray FancyZonesData::SerializeDeviceInfos() const
{ {
std::scoped_lock lock{ dataLock };
json::JsonArray DeviceInfosJSON{}; json::JsonArray DeviceInfosJSON{};
for (const auto& [deviceID, deviceData] : deviceInfoMap) for (const auto& [deviceID, deviceData] : deviceInfoMap)
{ {
if (deviceData.activeZoneSet.type != ZoneSetLayoutType::Blank) { if (deviceData.activeZoneSet.type != ZoneSetLayoutType::Blank)
{
DeviceInfosJSON.Append(DeviceInfoJSON::DeviceInfoJSON::ToJson(DeviceInfoJSON{ deviceID, deviceData })); DeviceInfosJSON.Append(DeviceInfoJSON::DeviceInfoJSON::ToJson(DeviceInfoJSON{ deviceID, deviceData }));
} }
} }
@@ -396,6 +422,7 @@ namespace JSONHelpers
bool FancyZonesData::ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON) bool FancyZonesData::ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON)
{ {
std::scoped_lock lock{ dataLock };
try try
{ {
auto customZoneSets = fancyZonesDataJSON.GetNamedArray(L"custom-zone-sets"); auto customZoneSets = fancyZonesDataJSON.GetNamedArray(L"custom-zone-sets");
@@ -418,6 +445,7 @@ namespace JSONHelpers
json::JsonArray FancyZonesData::SerializeCustomZoneSets() const json::JsonArray FancyZonesData::SerializeCustomZoneSets() const
{ {
std::scoped_lock lock{ dataLock };
json::JsonArray customZoneSetsJSON{}; json::JsonArray customZoneSetsJSON{};
for (const auto& [zoneSetId, zoneSetData] : customZoneSetsMap) for (const auto& [zoneSetId, zoneSetData] : customZoneSetsMap)
@@ -430,6 +458,7 @@ namespace JSONHelpers
void FancyZonesData::CustomZoneSetsToJsonFile(std::wstring_view filePath) const void FancyZonesData::CustomZoneSetsToJsonFile(std::wstring_view filePath) const
{ {
std::scoped_lock lock{ dataLock };
const auto& customZoneSetsJson = SerializeCustomZoneSets(); const auto& customZoneSetsJson = SerializeCustomZoneSets();
json::JsonObject root{}; json::JsonObject root{};
root.SetNamedValue(L"custom-zone-sets", customZoneSetsJson); root.SetNamedValue(L"custom-zone-sets", customZoneSetsJson);
@@ -438,6 +467,7 @@ namespace JSONHelpers
void FancyZonesData::LoadFancyZonesData() void FancyZonesData::LoadFancyZonesData()
{ {
std::scoped_lock lock{ dataLock };
std::wstring jsonFilePath = GetPersistFancyZonesJSONPath(); std::wstring jsonFilePath = GetPersistFancyZonesJSONPath();
if (!std::filesystem::exists(jsonFilePath)) if (!std::filesystem::exists(jsonFilePath))
@@ -461,6 +491,7 @@ namespace JSONHelpers
void FancyZonesData::SaveFancyZonesData() const void FancyZonesData::SaveFancyZonesData() const
{ {
std::scoped_lock lock{ dataLock };
json::JsonObject root{}; json::JsonObject root{};
root.SetNamedValue(L"app-zone-history", SerializeAppZoneHistory()); root.SetNamedValue(L"app-zone-history", SerializeAppZoneHistory());
@@ -474,6 +505,7 @@ namespace JSONHelpers
{ {
std::wregex ex(L"^[0-9]{3,4}_[0-9]{3,4}$"); std::wregex ex(L"^[0-9]{3,4}_[0-9]{3,4}$");
std::scoped_lock lock{ dataLock };
wchar_t key[256]; wchar_t key[256];
StringCchPrintf(key, ARRAYSIZE(key), L"%s", RegistryHelpers::REG_SETTINGS); StringCchPrintf(key, ARRAYSIZE(key), L"%s", RegistryHelpers::REG_SETTINGS);
HKEY hkey; HKEY hkey;
@@ -521,6 +553,7 @@ namespace JSONHelpers
void FancyZonesData::MigrateDeviceInfoFromRegistry(const std::wstring& deviceId) void FancyZonesData::MigrateDeviceInfoFromRegistry(const std::wstring& deviceId)
{ {
std::scoped_lock lock{ dataLock };
wchar_t key[256]; wchar_t key[256];
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", RegistryHelpers::REG_SETTINGS, deviceId.c_str()); StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", RegistryHelpers::REG_SETTINGS, deviceId.c_str());
@@ -546,6 +579,7 @@ namespace JSONHelpers
void FancyZonesData::MigrateCustomZoneSetsFromRegistry() void FancyZonesData::MigrateCustomZoneSetsFromRegistry()
{ {
std::scoped_lock lock{ dataLock };
wchar_t key[256]; wchar_t key[256];
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", RegistryHelpers::REG_SETTINGS, L"Layouts"); StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", RegistryHelpers::REG_SETTINGS, L"Layouts");
HKEY hkey; HKEY hkey;
@@ -574,8 +608,7 @@ namespace JSONHelpers
} }
switch (zoneSetData.type) switch (zoneSetData.type)
{ {
case CustomLayoutType::Grid: case CustomLayoutType::Grid: {
{
int j = 5; int j = 5;
GridLayoutInfo zoneSetInfo(GridLayoutInfo::Minimal{ .rows = data[j++], .columns = data[j++] }); GridLayoutInfo zoneSetInfo(GridLayoutInfo::Minimal{ .rows = data[j++], .columns = data[j++] });
@@ -599,8 +632,7 @@ namespace JSONHelpers
zoneSetData.info = zoneSetInfo; zoneSetData.info = zoneSetInfo;
break; break;
} }
case CustomLayoutType::Canvas: case CustomLayoutType::Canvas: {
{
CanvasLayoutInfo info; CanvasLayoutInfo info;
int j = 5; int j = 5;
@@ -880,8 +912,7 @@ namespace JSONHelpers
result.SetNamedValue(L"name", json::value(customZoneSet.data.name)); result.SetNamedValue(L"name", json::value(customZoneSet.data.name));
switch (customZoneSet.data.type) switch (customZoneSet.data.type)
{ {
case CustomLayoutType::Canvas: case CustomLayoutType::Canvas: {
{
result.SetNamedValue(L"type", json::value(L"canvas")); result.SetNamedValue(L"type", json::value(L"canvas"));
CanvasLayoutInfo info = std::get<CanvasLayoutInfo>(customZoneSet.data.info); CanvasLayoutInfo info = std::get<CanvasLayoutInfo>(customZoneSet.data.info);
@@ -889,8 +920,7 @@ namespace JSONHelpers
break; break;
} }
case CustomLayoutType::Grid: case CustomLayoutType::Grid: {
{
result.SetNamedValue(L"type", json::value(L"grid")); result.SetNamedValue(L"type", json::value(L"grid"));
GridLayoutInfo gridInfo = std::get<GridLayoutInfo>(customZoneSet.data.info); GridLayoutInfo gridInfo = std::get<GridLayoutInfo>(customZoneSet.data.info);

View File

@@ -2,6 +2,7 @@
#include <common/settings_helpers.h> #include <common/settings_helpers.h>
#include <common/json.h> #include <common/json.h>
#include <mutex>
#include <string> #include <string>
#include <strsafe.h> #include <strsafe.h>
@@ -159,12 +160,28 @@ namespace JSONHelpers
class FancyZonesData class FancyZonesData
{ {
mutable std::recursive_mutex dataLock;
public: public:
FancyZonesData(); FancyZonesData();
const std::wstring& GetPersistFancyZonesJSONPath() const; inline const std::wstring& GetPersistFancyZonesJSONPath() const
{
return jsonFilePath;
}
json::JsonObject GetPersistFancyZonesJSON(); json::JsonObject GetPersistFancyZonesJSON();
std::optional<DeviceInfoData> FindDeviceInfo(const std::wstring& zoneWindowId) const;
std::optional<CustomZoneSetData> FindCustomZoneSet(const std::wstring& guuid) const;
inline const std::wstring GetActiveDeviceId() const
{
std::scoped_lock lock{ dataLock };
return activeDeviceId;
}
#if defined(UNIT_TESTS)
inline const std::unordered_map<std::wstring, DeviceInfoData>& GetDeviceInfoMap() const inline const std::unordered_map<std::wstring, DeviceInfoData>& GetDeviceInfoMap() const
{ {
return deviceInfoMap; return deviceInfoMap;
@@ -180,13 +197,19 @@ namespace JSONHelpers
return appZoneHistoryMap; return appZoneHistoryMap;
} }
inline const std::wstring GetActiveDeviceId() const inline void clear_data()
{ {
return activeDeviceId; appliedZoneSetsMap.clear();
appZoneHistoryMap.clear();
deviceInfoMap.clear();
customZoneSetsMap.clear();
activeDeviceId.clear();
} }
#endif
void SetActiveDeviceId(const std::wstring& deviceId) inline void SetActiveDeviceId(const std::wstring& deviceId)
{ {
std::scoped_lock lock{ dataLock };
activeDeviceId = deviceId; activeDeviceId = deviceId;
} }

View File

@@ -497,13 +497,15 @@ bool ZoneSet::CalculateCustomLayout(Rect workArea, int spacing) noexcept
if (SUCCEEDED_LOG(StringFromCLSID(m_config.Id, &guuidStr))) if (SUCCEEDED_LOG(StringFromCLSID(m_config.Id, &guuidStr)))
{ {
const std::wstring guuid = guuidStr.get(); const std::wstring guuid = guuidStr.get();
const auto& customZoneSets = JSONHelpers::FancyZonesDataInstance().GetCustomZoneSetsMap();
if (!customZoneSets.contains(guuid)) const auto zoneSetSearchResult = JSONHelpers::FancyZonesDataInstance().FindCustomZoneSet(guuid);
if (!zoneSetSearchResult.has_value())
{ {
return false; return false;
} }
const auto& zoneSet = customZoneSets.at(guuid); const auto& zoneSet = *zoneSetSearchResult;
if (zoneSet.type == JSONHelpers::CustomLayoutType::Canvas && std::holds_alternative<JSONHelpers::CanvasLayoutInfo>(zoneSet.info)) if (zoneSet.type == JSONHelpers::CustomLayoutType::Canvas && std::holds_alternative<JSONHelpers::CanvasLayoutInfo>(zoneSet.info))
{ {
const auto& zoneSetInfo = std::get<JSONHelpers::CanvasLayoutInfo>(zoneSet.info); const auto& zoneSetInfo = std::get<JSONHelpers::CanvasLayoutInfo>(zoneSet.info);

View File

@@ -280,14 +280,22 @@ public:
IFACEMETHODIMP MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled) noexcept; IFACEMETHODIMP MoveSizeUpdate(POINT const& ptScreen, bool dragEnabled) noexcept;
IFACEMETHODIMP MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept; IFACEMETHODIMP MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept;
IFACEMETHODIMP MoveSizeCancel() noexcept; IFACEMETHODIMP MoveSizeCancel() noexcept;
IFACEMETHODIMP_(bool) IsDragEnabled() noexcept { return m_dragEnabled; } IFACEMETHODIMP_(bool)
IFACEMETHODIMP_(void) MoveWindowIntoZoneByIndex(HWND window, int index) noexcept; IsDragEnabled() noexcept { return m_dragEnabled; }
IFACEMETHODIMP_(void) MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode) noexcept; IFACEMETHODIMP_(void)
IFACEMETHODIMP_(void) CycleActiveZoneSet(DWORD vkCode) noexcept; MoveWindowIntoZoneByIndex(HWND window, int index) noexcept;
IFACEMETHODIMP_(std::wstring) UniqueId() noexcept { return { m_uniqueId }; } IFACEMETHODIMP_(void)
IFACEMETHODIMP_(std::wstring) WorkAreaKey() noexcept { return { m_workArea }; } MoveWindowIntoZoneByDirection(HWND window, DWORD vkCode) noexcept;
IFACEMETHODIMP_(void) SaveWindowProcessToZoneIndex(HWND window) noexcept; IFACEMETHODIMP_(void)
IFACEMETHODIMP_(IZoneSet*) ActiveZoneSet() noexcept { return m_activeZoneSet.get(); } CycleActiveZoneSet(DWORD vkCode) noexcept;
IFACEMETHODIMP_(std::wstring)
UniqueId() noexcept { return { m_uniqueId }; }
IFACEMETHODIMP_(std::wstring)
WorkAreaKey() noexcept { return { m_workArea }; }
IFACEMETHODIMP_(void)
SaveWindowProcessToZoneIndex(HWND window) noexcept;
IFACEMETHODIMP_(IZoneSet*)
ActiveZoneSet() noexcept { return m_activeZoneSet.get(); }
protected: protected:
static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept; static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept;
@@ -559,15 +567,21 @@ void ZoneWindow::InitializeZoneSets(MONITORINFO const& mi) noexcept
void ZoneWindow::CalculateZoneSet() noexcept void ZoneWindow::CalculateZoneSet() noexcept
{ {
const auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance(); const auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();
const auto& deviceInfoMap = fancyZonesData.GetDeviceInfoMap(); const auto deviceInfoData = fancyZonesData.FindDeviceInfo(m_uniqueId);
const auto& activeDeviceId = fancyZonesData.GetActiveDeviceId(); const auto& activeDeviceId = fancyZonesData.GetActiveDeviceId();
const auto& activeZoneSet = deviceInfoMap.at(m_uniqueId).activeZoneSet;
if (!activeDeviceId.empty() && activeDeviceId != m_uniqueId) if (!activeDeviceId.empty() && activeDeviceId != m_uniqueId)
{ {
return; return;
} }
if (!deviceInfoData.has_value())
{
return;
}
const auto& activeZoneSet = deviceInfoData->activeZoneSet;
if (activeZoneSet.uuid.empty() || activeZoneSet.type == JSONHelpers::ZoneSetLayoutType::Blank) if (activeZoneSet.uuid.empty() || activeZoneSet.type == JSONHelpers::ZoneSetLayoutType::Blank)
{ {
return; return;
@@ -585,9 +599,9 @@ void ZoneWindow::CalculateZoneSet() noexcept
monitorInfo.cbSize = sizeof(monitorInfo); monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfoW(m_monitor, &monitorInfo)) if (GetMonitorInfoW(m_monitor, &monitorInfo))
{ {
bool showSpacing = deviceInfoMap.at(m_uniqueId).showSpacing; bool showSpacing = deviceInfoData->showSpacing;
int spacing = showSpacing ? deviceInfoMap.at(m_uniqueId).spacing : 0; int spacing = showSpacing ? deviceInfoData->spacing : 0;
int zoneCount = deviceInfoMap.at(m_uniqueId).zoneCount; int zoneCount = deviceInfoData->zoneCount;
zoneSet->CalculateZones(monitorInfo, zoneCount, spacing); zoneSet->CalculateZones(monitorInfo, zoneCount, spacing);
UpdateActiveZoneSet(zoneSet.get()); UpdateActiveZoneSet(zoneSet.get());
} }

View File

@@ -290,7 +290,7 @@ namespace FancyZonesUnitTests
m_fzCallback = fancyZones.as<IFancyZonesCallback>(); m_fzCallback = fancyZones.as<IFancyZonesCallback>();
Assert::IsTrue(m_fzCallback != nullptr); Assert::IsTrue(m_fzCallback != nullptr);
m_fancyZonesData = JSONHelpers::FancyZonesData(); m_fancyZonesData.clear_data();
} }
TEST_METHOD_CLEANUP(Cleanup) TEST_METHOD_CLEANUP(Cleanup)

File diff suppressed because it is too large Load Diff

View File

@@ -60,7 +60,7 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\..\common\Telemetry;..\..\..\..\;..\..\..\..\..\deps\cpprestsdk\include;..\..\;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..\..\..\common\Telemetry;..\..\..\..\;..\..\..\..\..\deps\cpprestsdk\include;..\..\;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>UNIT_TESTS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths> <UseFullPaths>true</UseFullPaths>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard> <LanguageStandard>stdcpplatest</LanguageStandard>
@@ -81,7 +81,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\..\..\common\Telemetry;..\..\..\..\;..\..\..\..\..\deps\cpprestsdk\include;..\..\;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..\..\..\common\Telemetry;..\..\..\..\;..\..\..\..\..\deps\cpprestsdk\include;..\..\;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>UNIT_TESTS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths> <UseFullPaths>true</UseFullPaths>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard> <LanguageStandard>stdcpplatest</LanguageStandard>

View File

@@ -68,7 +68,7 @@ namespace FancyZonesUnitTests
GUID guid; GUID guid;
Assert::AreEqual(S_OK, CoCreateGuid(&guid)); Assert::AreEqual(S_OK, CoCreateGuid(&guid));
return GuidString(guid); return GuidString(guid);
} }
TEST_METHOD_INITIALIZE(Init) TEST_METHOD_INITIALIZE(Init)
@@ -89,7 +89,7 @@ namespace FancyZonesUnitTests
Assert::IsFalse(std::filesystem::exists(ZoneWindowUtils::GetAppliedZoneSetTmpPath())); Assert::IsFalse(std::filesystem::exists(ZoneWindowUtils::GetAppliedZoneSetTmpPath()));
Assert::IsFalse(std::filesystem::exists(ZoneWindowUtils::GetCustomZoneSetsTmpPath())); Assert::IsFalse(std::filesystem::exists(ZoneWindowUtils::GetCustomZoneSetsTmpPath()));
m_fancyZonesData = JSONHelpers::FancyZonesData(); m_fancyZonesData.clear_data();
} }
TEST_METHOD_CLEANUP(Cleanup) TEST_METHOD_CLEANUP(Cleanup)
@@ -622,7 +622,7 @@ namespace FancyZonesUnitTests
const auto processPath = get_process_path(window); const auto processPath = get_process_path(window);
const auto deviceId = m_zoneWindow->UniqueId(); const auto deviceId = m_zoneWindow->UniqueId();
const auto zoneSetId = m_zoneWindow->ActiveZoneSet()->Id(); const auto zoneSetId = m_zoneWindow->ActiveZoneSet()->Id();
//fill app zone history map //fill app zone history map
Assert::IsTrue(m_fancyZonesData.SetAppLastZone(window, deviceId, GuidString(zoneSetId), 0)); Assert::IsTrue(m_fancyZonesData.SetAppLastZone(window, deviceId, GuidString(zoneSetId), 0));
Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size()); Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size());