diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index 2ad1d46972..703fa28004 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -74,6 +75,7 @@ public: FancyZonesDataInstance().ReplaceZoneSettingsFileFromOlderVersions(); LayoutHotkeys::instance().LoadData(); CustomLayouts::instance().LoadData(); + AppZoneHistory::instance().LoadData(); } // IFancyZones @@ -275,6 +277,7 @@ FancyZones::Run() noexcept }); FancyZonesDataInstance().SetVirtualDesktopCheckCallback(std::bind(&VirtualDesktop::IsVirtualDesktopIdSavedInRegistry, &m_virtualDesktop, std::placeholders::_1)); + AppZoneHistory::instance().SetVirtualDesktopCheckCallback(std::bind(&VirtualDesktop::IsVirtualDesktopIdSavedInRegistry, &m_virtualDesktop, std::placeholders::_1)); } // IFancyZones @@ -334,14 +337,14 @@ void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr workA { _TRACER_; auto& fancyZonesData = FancyZonesDataInstance(); - if (!fancyZonesData.IsAnotherWindowOfApplicationInstanceZoned(window, workArea->UniqueId())) + if (!AppZoneHistory::instance().IsAnotherWindowOfApplicationInstanceZoned(window, workArea->UniqueId())) { if (workArea) { Trace::FancyZones::SnapNewWindowIntoZone(workArea->ZoneSet()); } m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, workArea); - fancyZonesData.UpdateProcessIdToHandleMap(window, workArea->UniqueId()); + AppZoneHistory::instance().UpdateProcessIdToHandleMap(window, workArea->UniqueId()); } } diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp index 057f53512c..25e260d908 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -167,9 +168,7 @@ void FancyZonesData::ReplaceZoneSettingsFileFromOlderVersions() { json::JsonObject fancyZonesDataJSON = GetPersistFancyZonesJSON(); - //appZoneHistoryMap = JSONHelpers::ParseAppZoneHistory(fancyZonesDataJSON); //deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON); - //customZoneSetsMap = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON); auto customLayouts = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON); if (customLayouts) @@ -204,12 +203,6 @@ const JSONHelpers::TDeviceInfoMap& FancyZonesData::GetDeviceInfoMap() const return deviceInfoMap; } -const std::unordered_map>& FancyZonesData::GetAppZoneHistoryMap() const -{ - std::scoped_lock lock{ dataLock }; - return appZoneHistoryMap; -} - std::optional FancyZonesData::FindDeviceInfo(const FancyZonesDataTypes::DeviceIdData& id) const { std::scoped_lock lock{ dataLock }; @@ -353,7 +346,8 @@ void FancyZonesData::SyncVirtualDesktops(GUID currentVirtualDesktopId) Logger::info(L"Update Virtual Desktop id to {}", virtualDesktopIdStr.get()); } - SaveAppZoneHistoryAndZoneSettings(); + SaveZoneSettings(); + AppZoneHistory::instance().SaveData(); } } @@ -378,7 +372,7 @@ void FancyZonesData::RemoveDeletedDesktops(const std::vector& activeDeskto Logger::info(L"Remove Virtual Desktop id {}", virtualDesktopIdStr.get()); } - RemoveDesktopAppZoneHistory(desktopId); + AppZoneHistory::instance().RemoveDesktopAppZoneHistory(desktopId); it = deviceInfoMap.erase(it); dirtyFlag = true; continue; @@ -389,204 +383,11 @@ void FancyZonesData::RemoveDeletedDesktops(const std::vector& activeDeskto if (dirtyFlag) { - SaveAppZoneHistoryAndZoneSettings(); + SaveZoneSettings(); + AppZoneHistory::instance().SaveData(); } } -bool FancyZonesData::IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const -{ - std::scoped_lock lock{ dataLock }; - auto processPath = get_process_path(window); - if (!processPath.empty()) - { - auto history = appZoneHistoryMap.find(processPath); - if (history != std::end(appZoneHistoryMap)) - { - auto& perDesktopData = history->second; - for (auto& data : perDesktopData) - { - if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) - { - DWORD processId = 0; - GetWindowThreadProcessId(window, &processId); - - auto processIdIt = data.processIdToHandleMap.find(processId); - - if (processIdIt == std::end(data.processIdToHandleMap)) - { - return false; - } - else if (processIdIt->second != window && IsWindow(processIdIt->second)) - { - return true; - } - } - } - } - } - - return false; -} - -void FancyZonesData::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) -{ - std::scoped_lock lock{ dataLock }; - auto processPath = get_process_path(window); - if (!processPath.empty()) - { - auto history = appZoneHistoryMap.find(processPath); - if (history != std::end(appZoneHistoryMap)) - { - auto& perDesktopData = history->second; - for (auto& data : perDesktopData) - { - if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) - { - DWORD processId = 0; - GetWindowThreadProcessId(window, &processId); - data.processIdToHandleMap[processId] = window; - break; - } - } - } - } -} - -ZoneIndexSet FancyZonesData::GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const -{ - std::scoped_lock lock{ dataLock }; - auto processPath = get_process_path(window); - if (!processPath.empty()) - { - auto history = appZoneHistoryMap.find(processPath); - if (history != std::end(appZoneHistoryMap)) - { - const auto& perDesktopData = history->second; - for (const auto& data : perDesktopData) - { - if (data.zoneSetUuid == zoneSetId && data.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) - { - return data.zoneIndexSet; - } - } - } - } - - return {}; -} - -bool FancyZonesData::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) -{ - _TRACER_; - std::scoped_lock lock{ dataLock }; - auto processPath = get_process_path(window); - if (!processPath.empty()) - { - auto history = appZoneHistoryMap.find(processPath); - if (history != std::end(appZoneHistoryMap)) - { - auto& perDesktopData = history->second; - for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);) - { - if (data->deviceId.isEqualWithNullVirtualDesktopId(deviceId) && data->zoneSetUuid == zoneSetId) - { - if (!IsAnotherWindowOfApplicationInstanceZoned(window, deviceId)) - { - DWORD processId = 0; - GetWindowThreadProcessId(window, &processId); - - data->processIdToHandleMap.erase(processId); - } - - // if there is another instance of same application placed in the same zone don't erase history - ZoneIndex windowZoneStamp = reinterpret_cast(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)); - for (auto placedWindow : data->processIdToHandleMap) - { - ZoneIndex placedWindowZoneStamp = reinterpret_cast(::GetProp(placedWindow.second, ZonedWindowProperties::PropertyMultipleZoneID)); - if (IsWindow(placedWindow.second) && (windowZoneStamp == placedWindowZoneStamp)) - { - return false; - } - } - - data = perDesktopData.erase(data); - if (perDesktopData.empty()) - { - appZoneHistoryMap.erase(processPath); - } - SaveAppZoneHistory(); - return true; - } - else - { - ++data; - } - } - } - } - - return false; -} - -bool FancyZonesData::SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet) -{ - _TRACER_; - std::scoped_lock lock{ dataLock }; - - if (IsAnotherWindowOfApplicationInstanceZoned(window, deviceId)) - { - return false; - } - - auto processPath = get_process_path(window); - if (processPath.empty()) - { - return false; - } - - DWORD processId = 0; - GetWindowThreadProcessId(window, &processId); - - auto history = appZoneHistoryMap.find(processPath); - if (history != std::end(appZoneHistoryMap)) - { - auto& perDesktopData = history->second; - for (auto& data : perDesktopData) - { - if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) - { - // application already has history on this work area, update it with new window position - data.processIdToHandleMap[processId] = window; - data.zoneSetUuid = zoneSetId; - data.zoneIndexSet = zoneIndexSet; - SaveAppZoneHistory(); - return true; - } - } - } - - std::unordered_map processIdToHandleMap{}; - processIdToHandleMap[processId] = window; - FancyZonesDataTypes::AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap, - .zoneSetUuid = zoneSetId, - .deviceId = deviceId, - .zoneIndexSet = zoneIndexSet }; - - if (appZoneHistoryMap.contains(processPath)) - { - // application already has history but on other desktop, add with new desktop info - appZoneHistoryMap[processPath].push_back(data); - } - else - { - // new application, create entry in app zone history map - appZoneHistoryMap[processPath] = std::vector{ data }; - } - - SaveAppZoneHistory(); - return true; -} - void FancyZonesData::SetActiveZoneSet(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& data) { std::scoped_lock lock{ dataLock }; @@ -635,23 +436,17 @@ void FancyZonesData::LoadFancyZonesData() { if (!std::filesystem::exists(zonesSettingsFileName)) { - SaveAppZoneHistoryAndZoneSettings(); + SaveZoneSettings(); + AppZoneHistory::instance().SaveData(); } else { json::JsonObject fancyZonesDataJSON = GetPersistFancyZonesJSON(); - appZoneHistoryMap = JSONHelpers::ParseAppZoneHistory(fancyZonesDataJSON); deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON); } } -void FancyZonesData::SaveAppZoneHistoryAndZoneSettings() const -{ - SaveZoneSettings(); - SaveAppZoneHistory(); -} - void FancyZonesData::SaveZoneSettings() const { _TRACER_; @@ -684,41 +479,6 @@ void FancyZonesData::SaveZoneSettings() const } } -void FancyZonesData::SaveAppZoneHistory() const -{ - _TRACER_; - std::scoped_lock lock{ dataLock }; - - bool dirtyFlag = false; - std::unordered_map> updatedHistory; - if (m_virtualDesktopCheckCallback) - { - for (const auto& [path, dataVector] : appZoneHistoryMap) - { - auto updatedVector = dataVector; - for (auto& data : updatedVector) - { - if (!m_virtualDesktopCheckCallback(data.deviceId.virtualDesktopId)) - { - data.deviceId.virtualDesktopId = GUID_NULL; - dirtyFlag = true; - } - } - - updatedHistory.insert(std::make_pair(path, updatedVector)); - } - } - - if (dirtyFlag) - { - JSONHelpers::SaveAppZoneHistory(appZoneHistoryFileName, updatedHistory); - } - else - { - JSONHelpers::SaveAppZoneHistory(appZoneHistoryFileName, appZoneHistoryMap); - } -} - void FancyZonesData::SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors, const std::wstring& virtualDesktopId, const HMONITOR& targetMonitor, const std::vector>& allMonitors) const { JSONHelpers::EditorArgs argsJson; /* json arguments */ @@ -782,31 +542,3 @@ void FancyZonesData::SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors json::to_file(editorParametersFileName, JSONHelpers::EditorArgs::ToJson(argsJson)); } - -void FancyZonesData::RemoveDesktopAppZoneHistory(GUID desktopId) -{ - for (auto it = std::begin(appZoneHistoryMap); it != std::end(appZoneHistoryMap);) - { - auto& perDesktopData = it->second; - for (auto desktopIt = std::begin(perDesktopData); desktopIt != std::end(perDesktopData);) - { - if (desktopIt->deviceId.virtualDesktopId == desktopId) - { - desktopIt = perDesktopData.erase(desktopIt); - } - else - { - ++desktopIt; - } - } - - if (perDesktopData.empty()) - { - it = appZoneHistoryMap.erase(it); - } - else - { - ++it; - } - } -} diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h index 35859d261f..738dc7c62e 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h @@ -48,7 +48,6 @@ public: std::optional FindDeviceInfo(const FancyZonesDataTypes::DeviceIdData& id) const; const JSONHelpers::TDeviceInfoMap& GetDeviceInfoMap() const; - const std::unordered_map>& GetAppZoneHistoryMap() const; inline const std::wstring& GetZonesSettingsFileName() const { @@ -65,20 +64,12 @@ public: void SyncVirtualDesktops(GUID desktopId); void RemoveDeletedDesktops(const std::vector& activeDesktops); - bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const; - void UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId); - ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const; - bool RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId); - bool SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet); - void SetActiveZoneSet(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& zoneSet); json::JsonObject GetPersistFancyZonesJSON(); void LoadFancyZonesData(); - void SaveAppZoneHistoryAndZoneSettings() const; void SaveZoneSettings() const; - void SaveAppZoneHistory() const; void SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors, const std::wstring& virtualDesktopId, const HMONITOR& targetMonitor, const std::vector>& allMonitors) const; @@ -123,8 +114,6 @@ private: return result + L"\\" + std::wstring(L"zones-settings.json"); } #endif - void RemoveDesktopAppZoneHistory(GUID desktopId); - // Maps app path to app's zone history data std::unordered_map> appZoneHistoryMap{}; // Maps device unique ID to device data diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp new file mode 100644 index 0000000000..0df5f11ba6 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp @@ -0,0 +1,327 @@ +#include "../pch.h" +#include "AppZoneHistory.h" + +#include +#include +#include + +#include +#include + +AppZoneHistory::AppZoneHistory() +{ +} + +AppZoneHistory& AppZoneHistory::instance() +{ + static AppZoneHistory self; + return self; +} + +void AppZoneHistory::SetVirtualDesktopCheckCallback(std::function callback) +{ + m_virtualDesktopCheckCallback = callback; +} + +void AppZoneHistory::LoadData() +{ + auto file = AppZoneHistoryFileName(); + auto data = json::from_file(file); + + try + { + if (data) + { + m_history = JSONHelpers::ParseAppZoneHistory(data.value()); + } + else + { + m_history.clear(); + Logger::error(L"app-zone-history.json file is missing or malformed"); + } + } + catch (const winrt::hresult_error& e) + { + Logger::error(L"Parsing app-zone-history error: {}", e.message()); + } +} + +void AppZoneHistory::SaveData() +{ + _TRACER_; + + bool dirtyFlag = false; + std::unordered_map> updatedHistory; + if (m_virtualDesktopCheckCallback) + { + for (const auto& [path, dataVector] : m_history) + { + auto updatedVector = dataVector; + for (auto& data : updatedVector) + { + if (!m_virtualDesktopCheckCallback(data.deviceId.virtualDesktopId)) + { + data.deviceId.virtualDesktopId = GUID_NULL; + dirtyFlag = true; + } + } + + updatedHistory.insert(std::make_pair(path, updatedVector)); + } + } + + if (dirtyFlag) + { + JSONHelpers::SaveAppZoneHistory(AppZoneHistoryFileName(), updatedHistory); + } + else + { + JSONHelpers::SaveAppZoneHistory(AppZoneHistoryFileName(), m_history); + } +} + +bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet) +{ + _TRACER_; + + if (IsAnotherWindowOfApplicationInstanceZoned(window, deviceId)) + { + return false; + } + + auto processPath = get_process_path(window); + if (processPath.empty()) + { + return false; + } + + DWORD processId = 0; + GetWindowThreadProcessId(window, &processId); + + auto history = m_history.find(processPath); + if (history != std::end(m_history)) + { + auto& perDesktopData = history->second; + for (auto& data : perDesktopData) + { + if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) + { + // application already has history on this work area, update it with new window position + data.processIdToHandleMap[processId] = window; + data.zoneSetUuid = zoneSetId; + data.zoneIndexSet = zoneIndexSet; + SaveData(); + return true; + } + } + } + + std::unordered_map processIdToHandleMap{}; + processIdToHandleMap[processId] = window; + FancyZonesDataTypes::AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap, + .zoneSetUuid = zoneSetId, + .deviceId = deviceId, + .zoneIndexSet = zoneIndexSet }; + + if (m_history.contains(processPath)) + { + // application already has history but on other desktop, add with new desktop info + m_history[processPath].push_back(data); + } + else + { + // new application, create entry in app zone history map + m_history[processPath] = std::vector{ data }; + } + + SaveData(); + return true; +} + +bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) +{ + _TRACER_; + + auto processPath = get_process_path(window); + if (!processPath.empty()) + { + auto history = m_history.find(processPath); + if (history != std::end(m_history)) + { + auto& perDesktopData = history->second; + for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);) + { + if (data->deviceId.isEqualWithNullVirtualDesktopId(deviceId) && data->zoneSetUuid == zoneSetId) + { + if (!IsAnotherWindowOfApplicationInstanceZoned(window, deviceId)) + { + DWORD processId = 0; + GetWindowThreadProcessId(window, &processId); + + data->processIdToHandleMap.erase(processId); + } + + // if there is another instance of same application placed in the same zone don't erase history + ZoneIndex windowZoneStamp = reinterpret_cast(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)); + for (auto placedWindow : data->processIdToHandleMap) + { + ZoneIndex placedWindowZoneStamp = reinterpret_cast(::GetProp(placedWindow.second, ZonedWindowProperties::PropertyMultipleZoneID)); + if (IsWindow(placedWindow.second) && (windowZoneStamp == placedWindowZoneStamp)) + { + return false; + } + } + + data = perDesktopData.erase(data); + if (perDesktopData.empty()) + { + m_history.erase(processPath); + } + SaveData(); + return true; + } + else + { + ++data; + } + } + } + } + + return false; +} + +void AppZoneHistory::RemoveApp(const std::wstring& appPath) +{ + m_history.erase(appPath); +} + +const AppZoneHistory::TAppZoneHistoryMap& AppZoneHistory::GetFullAppZoneHistory() const noexcept +{ + return m_history; +} + +std::optional AppZoneHistory::GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept +{ + auto iter = m_history.find(appPath); + if (iter != m_history.end()) + { + auto historyVector = iter->second; + for (const auto& history : historyVector) + { + if (history.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) + { + return history; + } + } + } + + return std::nullopt; +} + +bool AppZoneHistory::IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept +{ + auto processPath = get_process_path(window); + if (!processPath.empty()) + { + auto history = m_history.find(processPath); + if (history != std::end(m_history)) + { + auto& perDesktopData = history->second; + for (auto& data : perDesktopData) + { + if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) + { + DWORD processId = 0; + GetWindowThreadProcessId(window, &processId); + + auto processIdIt = data.processIdToHandleMap.find(processId); + + if (processIdIt == std::end(data.processIdToHandleMap)) + { + return false; + } + else if (processIdIt->second != window && IsWindow(processIdIt->second)) + { + return true; + } + } + } + } + } + + return false; +} + +void AppZoneHistory::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) +{ + auto processPath = get_process_path(window); + if (!processPath.empty()) + { + auto history = m_history.find(processPath); + if (history != std::end(m_history)) + { + auto& perDesktopData = history->second; + for (auto& data : perDesktopData) + { + if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) + { + DWORD processId = 0; + GetWindowThreadProcessId(window, &processId); + data.processIdToHandleMap[processId] = window; + break; + } + } + } + } +} + +ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const +{ + auto processPath = get_process_path(window); + if (!processPath.empty()) + { + auto history = m_history.find(processPath); + if (history != std::end(m_history)) + { + const auto& perDesktopData = history->second; + for (const auto& data : perDesktopData) + { + if (data.zoneSetUuid == zoneSetId && data.deviceId.isEqualWithNullVirtualDesktopId(deviceId)) + { + return data.zoneIndexSet; + } + } + } + } + + return {}; +} + +void AppZoneHistory::RemoveDesktopAppZoneHistory(GUID desktopId) +{ + for (auto it = std::begin(m_history); it != std::end(m_history);) + { + auto& perDesktopData = it->second; + for (auto desktopIt = std::begin(perDesktopData); desktopIt != std::end(perDesktopData);) + { + if (desktopIt->deviceId.virtualDesktopId == desktopId) + { + desktopIt = perDesktopData.erase(desktopIt); + } + else + { + ++desktopIt; + } + } + + if (perDesktopData.empty()) + { + it = m_history.erase(it); + } + else + { + ++it; + } + } +} diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.h new file mode 100644 index 0000000000..00d57fd4ee --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include + +class AppZoneHistory +{ +public: + using TAppZoneHistoryMap = std::unordered_map>; + + static AppZoneHistory& instance(); + + inline static std::wstring AppZoneHistoryFileName() + { + std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey); +#if defined(UNIT_TESTS) + return saveFolderPath + L"\\test-app-zone-history.json"; +#endif + return saveFolderPath + L"\\app-zone-history.json"; + } + + void SetVirtualDesktopCheckCallback(std::function callback); + + void LoadData(); + void SaveData(); + + bool SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet); + bool RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId); + + void RemoveApp(const std::wstring& appPath); + + const TAppZoneHistoryMap& GetFullAppZoneHistory() const noexcept; + std::optional GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept; + + bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept; + void UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId); + ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const; + + void RemoveDesktopAppZoneHistory(GUID desktopId); + +private: + AppZoneHistory(); + ~AppZoneHistory() = default; + + TAppZoneHistoryMap m_history; + std::function m_virtualDesktopCheckCallback; +}; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj index e23a8a9b94..ea7147628f 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj @@ -38,6 +38,7 @@ + @@ -68,6 +69,10 @@ + + ../pch.h + ../pch.h + ../pch.h ../pch.h diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters index 7194abff55..79f395d59e 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters @@ -90,6 +90,9 @@ Header Files + + Header Files + Header Files @@ -167,6 +170,9 @@ Source Files + + Source Files + diff --git a/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp b/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp index 7e39209037..3b2e4b565b 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp @@ -7,7 +7,7 @@ #include #include -#include "FancyZonesData.h" +#include "FancyZonesData/AppZoneHistory.h" #include "Settings.h" #include "WorkArea.h" #include "util.h" @@ -261,7 +261,7 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st wil::unique_cotaskmem_string guidString; if (SUCCEEDED_LOG(StringFromCLSID(zoneSet->Id(), &guidString))) { - FancyZonesDataInstance().RemoveAppLastZone(window, workAreaPtr->UniqueId(), guidString.get()); + AppZoneHistory::instance().RemoveAppLastZone(window, workAreaPtr->UniqueId(), guidString.get()); } } } diff --git a/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp b/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp index a5dc98fa4f..28a9a4326b 100644 --- a/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp @@ -5,6 +5,7 @@ #include #include "FancyZonesData.h" +#include "FancyZonesData/AppZoneHistory.h" #include "FancyZonesDataTypes.h" #include "ZonesOverlay.h" #include "trace.h" @@ -379,7 +380,7 @@ WorkArea::SaveWindowProcessToZoneIndex(HWND window) noexcept OLECHAR* guidString; if (StringFromCLSID(m_zoneSet->Id(), &guidString) == S_OK) { - FancyZonesDataInstance().SetAppLastZones(window, m_uniqueId, guidString, zoneIndexSet); + AppZoneHistory::instance().SetAppLastZones(window, m_uniqueId, guidString, zoneIndexSet); } CoTaskMemFree(guidString); @@ -395,7 +396,7 @@ WorkArea::GetWindowZoneIndexes(HWND window) const noexcept wil::unique_cotaskmem_string zoneSetId; if (SUCCEEDED(StringFromCLSID(m_zoneSet->Id(), &zoneSetId))) { - return FancyZonesDataInstance().GetAppLastZoneIndexSet(window, m_uniqueId, zoneSetId.get()); + return AppZoneHistory::instance().GetAppLastZoneIndexSet(window, m_uniqueId, zoneSetId.get()); } } return {}; diff --git a/src/modules/fancyzones/FancyZonesLib/trace.cpp b/src/modules/fancyzones/FancyZonesLib/trace.cpp index 38fc2c80a1..1c8fa3f091 100644 --- a/src/modules/fancyzones/FancyZonesLib/trace.cpp +++ b/src/modules/fancyzones/FancyZonesLib/trace.cpp @@ -3,6 +3,7 @@ #include "FancyZonesLib/ZoneSet.h" #include "FancyZonesLib/Settings.h" #include "FancyZonesLib/FancyZonesData.h" +#include "FancyZonesData/AppZoneHistory.h" #include "FancyZonesLib/FancyZonesData/CustomLayouts.h" #include "FancyZonesLib/FancyZonesData/LayoutHotkeys.h" #include "FancyZonesLib/FancyZonesDataTypes.h" @@ -145,7 +146,7 @@ void Trace::FancyZones::OnKeyDown(DWORD vkCode, bool win, bool control, bool inM void Trace::FancyZones::DataChanged() noexcept { const FancyZonesData& data = FancyZonesDataInstance(); - int appsHistorySize = static_cast(data.GetAppZoneHistoryMap().size()); + int appsHistorySize = static_cast(AppZoneHistory::instance().GetFullAppZoneHistory().size()); const auto& customZones = CustomLayouts::instance().GetAllLayouts(); const auto& devices = data.GetDeviceInfoMap(); auto quickKeysCount = LayoutHotkeys::instance().GetHotkeysCount(); diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/AppZoneHistoryTests.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/AppZoneHistoryTests.Spec.cpp new file mode 100644 index 0000000000..d843048617 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/AppZoneHistoryTests.Spec.cpp @@ -0,0 +1,129 @@ +#include "pch.h" +#include + +#include + +#include "util.h" + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace FancyZonesUnitTests +{ + TEST_CLASS (AppZoneHistoryUnitTests) + { + HINSTANCE m_hInst{}; + + TEST_METHOD_INITIALIZE(Init) + { + m_hInst = (HINSTANCE)GetModuleHandleW(nullptr); + AppZoneHistory::instance().LoadData(); + } + + TEST_METHOD_CLEANUP(CleanUp) + { + std::filesystem::remove(AppZoneHistory::instance().AppZoneHistoryFileName()); + } + + TEST_METHOD (AppLastZoneInvalidWindow) + { + const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; + const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = Mocks::Window(); + + Assert::IsTrue(std::vector{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); + + const int expectedZoneIndex = 1; + Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); + } + + TEST_METHOD (AppLastZoneNullWindow) + { + const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; + const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = nullptr; + + const int expectedZoneIndex = 1; + Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); + } + + TEST_METHOD (AppLastdeviceIdTest) + { + const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; + const FancyZonesDataTypes::DeviceIdData deviceId1{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const FancyZonesDataTypes::DeviceIdData deviceId2{ L"DELA026#5&10a58c63&0&UID16777489_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = Mocks::WindowCreate(m_hInst); + + const int expectedZoneIndex = 10; + Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId1, zoneSetId, { expectedZoneIndex })); + Assert::IsTrue(std::vector{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId1, zoneSetId)); + Assert::IsTrue(std::vector{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId2, zoneSetId)); + } + + TEST_METHOD (AppLastZoneSetIdTest) + { + const std::wstring zoneSetId1 = L"{B7A1F5A9-9DC2-4505-84AB-993253839093}"; + const std::wstring zoneSetId2 = L"{B7A1F5A9-9DC2-4505-84AB-993253839094}"; + const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = Mocks::WindowCreate(m_hInst); + + const int expectedZoneIndex = 10; + Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetId1, { expectedZoneIndex })); + Assert::IsTrue(std::vector{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId1)); + Assert::IsTrue(std::vector{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId2)); + } + + TEST_METHOD (AppLastZoneRemoveWindow) + { + const std::wstring zoneSetId = L"{B7A1F5A9-9DC2-4505-84AB-993253839093}"; + const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = Mocks::WindowCreate(m_hInst); + + Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetId, { 1 })); + Assert::IsTrue(AppZoneHistory::instance().RemoveAppLastZone(window, deviceId, zoneSetId)); + Assert::IsTrue(std::vector{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); + } + + TEST_METHOD (AppLastZoneRemoveUnknownWindow) + { + const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; + const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = Mocks::WindowCreate(m_hInst); + + Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, deviceId, zoneSetId)); + Assert::IsTrue(std::vector{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); + } + + TEST_METHOD (AppLastZoneRemoveUnknownZoneSetId) + { + const std::wstring zoneSetIdToInsert = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; + const std::wstring zoneSetIdToRemove = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F1}"; + const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = Mocks::WindowCreate(m_hInst); + + Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetIdToInsert, { 1 })); + Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, deviceId, zoneSetIdToRemove)); + Assert::IsTrue(std::vector{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetIdToInsert)); + } + + TEST_METHOD (AppLastZoneRemoveUnknownWindowId) + { + const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; + const FancyZonesDataTypes::DeviceIdData deviceIdToInsert{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const FancyZonesDataTypes::DeviceIdData deviceIdToRemove{ L"DELA026#5&10a58c63&0&UID16777489_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = Mocks::WindowCreate(m_hInst); + + Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceIdToInsert, zoneSetId, { 1 })); + Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, deviceIdToRemove, zoneSetId)); + Assert::IsTrue(std::vector{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceIdToInsert, zoneSetId)); + } + + TEST_METHOD (AppLastZoneRemoveNullWindow) + { + const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; + const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; + const auto window = Mocks::WindowCreate(m_hInst); + + Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(nullptr, deviceId, zoneSetId)); + } + }; +} \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/JsonHelpers.Tests.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/JsonHelpers.Tests.cpp index 0b6af79b12..04bead184a 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/JsonHelpers.Tests.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/JsonHelpers.Tests.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -1499,7 +1500,6 @@ namespace FancyZonesUnitTests std::filesystem::remove(jsonPath); } - Assert::IsFalse(fancyZonesData.GetAppZoneHistoryMap().empty()); Assert::IsFalse(fancyZonesData.GetDeviceInfoMap().empty()); } @@ -1509,11 +1509,10 @@ namespace FancyZonesUnitTests data.SetSettingsModulePath(m_moduleName); const auto& jsonPath = data.zonesSettingsFileName; - std::wofstream{ jsonPath.data(), std::ios::binary } << L"{ \"app-zone-history\": [], \"devices\": [{\"device-id\": \""; + std::wofstream{ jsonPath.data(), std::ios::binary } << L"{ \"devices\": [{\"device-id\": \""; data.LoadFancyZonesData(); - Assert::IsTrue(data.GetAppZoneHistoryMap().empty()); Assert::IsTrue(data.GetDeviceInfoMap().empty()); } @@ -1523,10 +1522,9 @@ namespace FancyZonesUnitTests data.SetSettingsModulePath(m_moduleName); const auto& jsonPath = data.zonesSettingsFileName; - std::wofstream{ jsonPath.data(), std::ios::binary } << L"{ \"app-zone-history\": [], \"devices\": [{\"device-id\": \"кириллица\"}], \"custom-zone-sets\": []}"; + std::wofstream{ jsonPath.data(), std::ios::binary } << L"{ \"devices\": [{\"device-id\": \"кириллица\"}], \"custom-zone-sets\": []}"; data.LoadFancyZonesData(); - Assert::IsTrue(data.GetAppZoneHistoryMap().empty()); Assert::IsTrue(data.GetDeviceInfoMap().empty()); } @@ -1536,10 +1534,9 @@ namespace FancyZonesUnitTests data.SetSettingsModulePath(m_moduleName); const auto& jsonPath = data.zonesSettingsFileName; - std::wofstream{ jsonPath.data(), std::ios::binary } << L"{ \"app-zone-history\": null, \"devices\": [{\"device-id\":\"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\",\"active-zoneset\":{\"uuid\":\"{568EBC3A-C09C-483E-A64D-6F1F2AF4E48D}\",\"type\":\"columns\"},\"editor-show-spacing\":true,\"editor-spacing\":16,\"editor-zone-count\":3}], \"custom-zone-sets\": []}"; + std::wofstream{ jsonPath.data(), std::ios::binary } << L"{ \"devices\": [{\"device-id\":\"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\",\"active-zoneset\":{\"uuid\":\"{568EBC3A-C09C-483E-A64D-6F1F2AF4E48D}\",\"type\":\"columns\"},\"editor-show-spacing\":true,\"editor-spacing\":16,\"editor-zone-count\":3}], \"custom-zone-sets\": null}"; data.LoadFancyZonesData(); - Assert::IsTrue(data.GetAppZoneHistoryMap().empty()); Assert::IsFalse(data.GetDeviceInfoMap().empty()); } @@ -1561,201 +1558,12 @@ namespace FancyZonesUnitTests data.SetSettingsModulePath(m_moduleName); const auto& jsonPath = data.zonesSettingsFileName; - data.SaveAppZoneHistoryAndZoneSettings(); + data.SaveZoneSettings(); bool actual = std::filesystem::exists(jsonPath); Assert::IsTrue(actual); } - TEST_METHOD (AppLastZoneIndex) - { - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const std::wstring zoneSetId = L"zoneset-uuid"; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - Assert::IsTrue(std::vector{} == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - - const int expectedZoneIndex = 10; - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex } )); - Assert::IsTrue(std::vector{ expectedZoneIndex } == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - } - - TEST_METHOD (AppLastZoneIndexZero) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - const int expectedZoneIndex = 0; - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); - Assert::IsTrue(std::vector{ expectedZoneIndex } == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - } - - TEST_METHOD (AppLastZoneIndexNegative) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - const ZoneIndex expectedZoneIndex = -1; - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); - Assert::IsTrue(std::vector{ expectedZoneIndex } == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - } - - TEST_METHOD (AppLastZoneIndexOverflow) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - const ZoneIndex expectedZoneIndex = ULLONG_MAX; - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); - Assert::IsTrue(std::vector{ expectedZoneIndex } == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - } - - TEST_METHOD (AppLastZoneIndexOverride) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - const int expectedZoneIndex = 3; - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId, { 1 })); - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId, { 2 })); - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); - Assert::IsTrue(std::vector{ expectedZoneIndex } == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - } - - TEST_METHOD (AppLastZoneInvalidWindow) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::Window(); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - Assert::IsTrue(std::vector{} == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - - const int expectedZoneIndex = 1; - Assert::IsFalse(data.SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); - } - - TEST_METHOD (AppLastZoneNullWindow) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = nullptr; - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - const int expectedZoneIndex = 1; - Assert::IsFalse(data.SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); - } - - TEST_METHOD (AppLastdeviceIdTest) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId1{ L"device-id-1" }; - const FancyZonesDataTypes::DeviceIdData deviceId2{ L"device-id-2" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - const int expectedZoneIndex = 10; - Assert::IsTrue(data.SetAppLastZones(window, deviceId1, zoneSetId, { expectedZoneIndex })); - Assert::IsTrue(std::vector{ expectedZoneIndex } == data.GetAppLastZoneIndexSet(window, deviceId1, zoneSetId)); - Assert::IsTrue(std::vector{} == data.GetAppLastZoneIndexSet(window, deviceId2, zoneSetId)); - } - - TEST_METHOD (AppLastZoneSetIdTest) - { - const std::wstring zoneSetId1 = L"zoneset-uuid-1"; - const std::wstring zoneSetId2 = L"zoneset-uuid-2"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - const int expectedZoneIndex = 10; - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId1, { expectedZoneIndex })); - Assert::IsTrue(std::vector{ expectedZoneIndex } == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId1)); - Assert::IsTrue(std::vector{} == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId2)); - } - - TEST_METHOD (AppLastZoneRemoveWindow) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetId, { 1 })); - Assert::IsTrue(data.RemoveAppLastZone(window, deviceId, zoneSetId)); - Assert::IsTrue(std::vector{} == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - } - - TEST_METHOD (AppLastZoneRemoveUnknownWindow) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - Assert::IsFalse(data.RemoveAppLastZone(window, deviceId, zoneSetId)); - Assert::IsTrue(std::vector{} == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); - } - - TEST_METHOD (AppLastZoneRemoveUnknownZoneSetId) - { - const std::wstring zoneSetIdToInsert = L"zoneset-uuid-to-insert"; - const std::wstring zoneSetIdToRemove = L"zoneset-uuid-to-remove"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - Assert::IsTrue(data.SetAppLastZones(window, deviceId, zoneSetIdToInsert, { 1 })); - Assert::IsFalse(data.RemoveAppLastZone(window, deviceId, zoneSetIdToRemove)); - Assert::IsTrue(std::vector{ 1 } == data.GetAppLastZoneIndexSet(window, deviceId, zoneSetIdToInsert)); - } - - TEST_METHOD (AppLastZoneRemoveUnknownWindowId) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceIdToInsert{ L"device-id-insert" }; - const FancyZonesDataTypes::DeviceIdData deviceIdToRemove{ L"device-id-remove" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - Assert::IsTrue(data.SetAppLastZones(window, deviceIdToInsert, zoneSetId, { 1 })); - Assert::IsFalse(data.RemoveAppLastZone(window, deviceIdToRemove, zoneSetId)); - Assert::IsTrue(std::vector{ 1 } == data.GetAppLastZoneIndexSet(window, deviceIdToInsert, zoneSetId)); - } - - TEST_METHOD (AppLastZoneRemoveNullWindow) - { - const std::wstring zoneSetId = L"zoneset-uuid"; - const FancyZonesDataTypes::DeviceIdData deviceId{ L"device-id" }; - const auto window = Mocks::WindowCreate(m_hInst); - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - - Assert::IsFalse(data.RemoveAppLastZone(nullptr, deviceId, zoneSetId)); - } - TEST_METHOD (AddDevice) { FancyZonesDataTypes::DeviceIdData expected{ diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj index 51f145c3a2..7bde9eb25b 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj @@ -41,6 +41,7 @@ + diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters index e2bdcd4df9..cb3fe292e9 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/UnitTests.vcxproj.filters @@ -51,6 +51,9 @@ Source Files + + Source Files + diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp index fb22baffea..972bdf5bac 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -211,31 +212,33 @@ namespace FancyZonesUnitTests OverlappingZonesAlgorithm m_overlappingAlgorithm = OverlappingZonesAlgorithm::Positional; bool m_showZoneText = true; - FancyZonesData& m_fancyZonesData = FancyZonesDataInstance(); - TEST_METHOD_INITIALIZE(Init) - { - m_hInst = (HINSTANCE)GetModuleHandleW(nullptr); + { + m_hInst = (HINSTANCE)GetModuleHandleW(nullptr); + + m_monitor = MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); + m_monitorInfo.cbSize = sizeof(m_monitorInfo); + Assert::AreNotEqual(0, GetMonitorInfoW(m_monitor, &m_monitorInfo)); - m_monitor = MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); - m_monitorInfo.cbSize = sizeof(m_monitorInfo); - Assert::AreNotEqual(0, GetMonitorInfoW(m_monitor, &m_monitorInfo)); - - m_uniqueId.deviceName = L"DELA026#5&10a58c63&0&UID16777488"; - m_uniqueId.width = m_monitorInfo.rcMonitor.right - m_monitorInfo.rcMonitor.left; - m_uniqueId.height = m_monitorInfo.rcMonitor.bottom - m_monitorInfo.rcMonitor.top; - CLSIDFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", &m_uniqueId.virtualDesktopId); + m_uniqueId.deviceName = L"DELA026#5&10a58c63&0&UID16777488"; + m_uniqueId.width = m_monitorInfo.rcMonitor.right - m_monitorInfo.rcMonitor.left; + m_uniqueId.height = m_monitorInfo.rcMonitor.bottom - m_monitorInfo.rcMonitor.top; + CLSIDFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", &m_uniqueId.virtualDesktopId); - m_fancyZonesData.SetSettingsModulePath(L"FancyZonesUnitTests"); - m_fancyZonesData.clear_data(); + m_zoneColors = ZoneColors{ + .primaryColor = FancyZonesUtils::HexToRGB(L"#4287f5"), + .borderColor = FancyZonesUtils::HexToRGB(L"#FFFFFF"), + .highlightColor = FancyZonesUtils::HexToRGB(L"#42eff5"), + .highlightOpacity = 50, + }; - m_zoneColors = ZoneColors{ - .primaryColor = FancyZonesUtils::HexToRGB(L"#4287f5"), - .borderColor = FancyZonesUtils::HexToRGB(L"#FFFFFF"), - .highlightColor = FancyZonesUtils::HexToRGB(L"#42eff5"), - .highlightOpacity = 50, - }; - } + AppZoneHistory::instance().LoadData(); + } + + TEST_METHOD_CLEANUP(CleanUp) + { + std::filesystem::remove(AppZoneHistory::AppZoneHistoryFileName()); + } public: TEST_METHOD (MoveSizeEnter) @@ -381,7 +384,7 @@ namespace FancyZonesUnitTests const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); - const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); + const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); const auto& appHistoryArray = actualAppZoneHistory.begin()->second; Assert::AreEqual((size_t)1, appHistoryArray.size()); @@ -398,7 +401,7 @@ namespace FancyZonesUnitTests workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); - const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); + const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); const auto& appHistoryArray = actualAppZoneHistory.begin()->second; Assert::AreEqual((size_t)1, appHistoryArray.size()); @@ -412,7 +415,7 @@ namespace FancyZonesUnitTests workArea->SaveWindowProcessToZoneIndex(nullptr); - const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); + const auto actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory(); Assert::IsTrue(actualAppZoneHistory.empty()); } @@ -427,7 +430,7 @@ namespace FancyZonesUnitTests workArea->SaveWindowProcessToZoneIndex(window); - const auto actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); + const auto actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory(); Assert::IsTrue(actualAppZoneHistory.empty()); } @@ -442,9 +445,9 @@ namespace FancyZonesUnitTests const auto zoneSetId = workArea->ZoneSet()->Id(); // fill app zone history map - Assert::IsTrue(m_fancyZonesData.SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 0 })); - Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size()); - const auto& appHistoryArray1 = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath); + Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 0 })); + Assert::AreEqual((size_t)1, AppZoneHistory::instance().GetFullAppZoneHistory().size()); + const auto& appHistoryArray1 = AppZoneHistory::instance().GetFullAppZoneHistory().at(processPath); Assert::AreEqual((size_t)1, appHistoryArray1.size()); Assert::IsTrue(std::vector{ 0 } == appHistoryArray1[0].zoneIndexSet); @@ -453,8 +456,8 @@ namespace FancyZonesUnitTests workArea->ZoneSet()->AddZone(zone); workArea->SaveWindowProcessToZoneIndex(window); - Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size()); - const auto& appHistoryArray2 = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath); + Assert::AreEqual((size_t)1, AppZoneHistory::instance().GetFullAppZoneHistory().size()); + const auto& appHistoryArray2 = AppZoneHistory::instance().GetFullAppZoneHistory().at(processPath); Assert::AreEqual((size_t)1, appHistoryArray2.size()); Assert::IsTrue(std::vector{ 0 } == appHistoryArray2[0].zoneIndexSet); } @@ -474,15 +477,15 @@ namespace FancyZonesUnitTests workArea->MoveWindowIntoZoneByIndex(window, 0); //fill app zone history map - Assert::IsTrue(m_fancyZonesData.SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 2 })); - Assert::AreEqual((size_t)1, m_fancyZonesData.GetAppZoneHistoryMap().size()); - const auto& appHistoryArray = m_fancyZonesData.GetAppZoneHistoryMap().at(processPath); + Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, Helpers::GuidToString(zoneSetId), { 2 })); + Assert::AreEqual((size_t)1, AppZoneHistory::instance().GetFullAppZoneHistory().size()); + const auto& appHistoryArray = AppZoneHistory::instance().GetFullAppZoneHistory().at(processPath); Assert::AreEqual((size_t)1, appHistoryArray.size()); Assert::IsTrue(std::vector{ 2 } == appHistoryArray[0].zoneIndexSet); workArea->SaveWindowProcessToZoneIndex(window); - const auto& actualAppZoneHistory = m_fancyZonesData.GetAppZoneHistoryMap(); + const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory(); Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); const auto& expected = workArea->ZoneSet()->GetZoneIndexSetFromWindow(window); const auto& actual = appHistoryArray[0].zoneIndexSet;