From 890b7f4286a95ced04d7da140b474f90fd4351ed Mon Sep 17 00:00:00 2001 From: Seraphima Zykova Date: Thu, 21 Sep 2023 13:47:56 +0300 Subject: [PATCH] [FancyZones]Fix for the scenario of layout reset when opening the FZEditor (#28556) * rename * moved applied layouts tests * changed work area id comparison * changed save * changed apply * changed clone * sync applied layouts * save last used vd * replace parent work area ids * proper time for sync * sync layouts considering last used virtual desktop * use ids from work areas on editor opening * update applied layouts tests * sync app zone history vd * fix test * release build fix * app zone history comparison * pass last used vd to sync * clean up unused * dpi unaware values * update GUID_NULL * use registry values only * added more tests * fix failing scenario * added replace condition to zone history * sync time * log * spellcheck * fix pch in project * fixed cloning layout --- .../FancyZonesLib/EditorParameters.cpp | 123 +++-- .../FancyZonesLib/EditorParameters.h | 5 +- .../fancyzones/FancyZonesLib/FancyZones.cpp | 82 +-- .../fancyzones/FancyZonesLib/FancyZonesData.h | 8 +- .../FancyZonesData/AppZoneHistory.cpp | 65 +-- .../FancyZonesData/AppZoneHistory.h | 12 +- .../FancyZonesData/AppliedLayouts.cpp | 155 +++--- .../FancyZonesData/AppliedLayouts.h | 10 +- .../FancyZonesData/LastUsedVirtualDesktop.cpp | 78 +++ .../FancyZonesData/LastUsedVirtualDesktop.h | 41 ++ .../FancyZonesLib/FancyZonesDataTypes.h | 11 +- .../FancyZonesLib/FancyZonesLib.vcxproj | 8 +- .../FancyZonesLib.vcxproj.filters | 10 +- .../FancyZonesLib/VirtualDesktop.cpp | 24 +- .../fancyzones/FancyZonesLib/VirtualDesktop.h | 2 - .../fancyzones/FancyZonesLib/WorkArea.cpp | 8 +- ...kAreaMap.cpp => WorkAreaConfiguration.cpp} | 36 +- ...rWorkAreaMap.h => WorkAreaConfiguration.h} | 15 +- .../UnitTests/AppZoneHistoryTests.Spec.cpp | 155 ++++++ .../UnitTests/AppliedLayoutsTests.Spec.cpp | 497 +++++++++++------- .../UnitTests/WorkAreaIdTests.Spec.cpp | 10 +- 21 files changed, 860 insertions(+), 495 deletions(-) create mode 100644 src/modules/fancyzones/FancyZonesLib/FancyZonesData/LastUsedVirtualDesktop.cpp create mode 100644 src/modules/fancyzones/FancyZonesLib/FancyZonesData/LastUsedVirtualDesktop.h rename src/modules/fancyzones/FancyZonesLib/{MonitorWorkAreaMap.cpp => WorkAreaConfiguration.cpp} (57%) rename src/modules/fancyzones/FancyZonesLib/{MonitorWorkAreaMap.h => WorkAreaConfiguration.h} (78%) diff --git a/src/modules/fancyzones/FancyZonesLib/EditorParameters.cpp b/src/modules/fancyzones/FancyZonesLib/EditorParameters.cpp index 26397eb1ba..b7a7ea4523 100644 --- a/src/modules/fancyzones/FancyZonesLib/EditorParameters.cpp +++ b/src/modules/fancyzones/FancyZonesLib/EditorParameters.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,31 @@ namespace JsonUtils int monitorHeight{}; bool isSelected = false; + bool FillFromWorkArea(const WorkArea* const workArea) + { + const auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(workArea->UniqueId().virtualDesktopId); + if (!virtualDesktopIdStr) + { + return false; + } + + const auto& monitorId = workArea->UniqueId().monitorId; + monitorName = monitorId.deviceId.id; + monitorInstanceId = monitorId.deviceId.instanceId; + monitorNumber = monitorId.deviceId.number; + monitorSerialNumber = monitorId.serialNumber; + + const auto& rect = workArea->GetWorkAreaRect(); + top = rect.top(); + left = rect.left(); + workAreaWidth = rect.width(); + workAreaHeight = rect.height(); + + virtualDesktop = virtualDesktopIdStr.value(); + + return true; + } + static json::JsonObject ToJson(const MonitorInfo& monitor) { json::JsonObject result{}; @@ -84,21 +110,8 @@ namespace JsonUtils }; } -bool EditorParameters::Save() noexcept +bool EditorParameters::Save(const WorkAreaConfiguration& configuration, OnThreadExecutor& dpiUnawareThread) noexcept { - const auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(VirtualDesktop::instance().GetCurrentVirtualDesktopId()); - if (!virtualDesktopIdStr) - { - Logger::error(L"Save editor params: invalid virtual desktop id"); - return false; - } - - OnThreadExecutor dpiUnawareThread; - dpiUnawareThread.submit(OnThreadExecutor::task_t{ [] { - SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE); - SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR_MIXED); - } }).wait(); - const bool spanZonesAcrossMonitors = FancyZonesSettings::settings().spanZonesAcrossMonitors; JsonUtils::EditorArgs argsJson; @@ -107,23 +120,31 @@ bool EditorParameters::Save() noexcept if (spanZonesAcrossMonitors) { - RECT combinedWorkArea; - dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&]() { - combinedWorkArea = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFOEX::rcWork>(); - - } }).wait(); - - RECT combinedMonitorArea = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFOEX::rcMonitor>(); + const auto& workArea = configuration.GetWorkArea(nullptr); + if (!workArea) + { + return false; + } JsonUtils::MonitorInfo monitorJson; - monitorJson.monitorName = ZonedWindowProperties::MultiMonitorName; - monitorJson.monitorInstanceId = ZonedWindowProperties::MultiMonitorInstance; - monitorJson.monitorNumber = 0; - monitorJson.virtualDesktop = virtualDesktopIdStr.value(); + if (!monitorJson.FillFromWorkArea(workArea)) + { + return false; + } + + RECT combinedWorkArea; + dpiUnawareThread.submit(OnThreadExecutor::task_t{ + [&]() { + combinedWorkArea = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFOEX::rcWork>(); + } }).wait(); + RECT combinedMonitorArea = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFOEX::rcMonitor>(); + + // use dpi-unaware values monitorJson.top = combinedWorkArea.top; monitorJson.left = combinedWorkArea.left; monitorJson.workAreaWidth = combinedWorkArea.right - combinedWorkArea.left; monitorJson.workAreaHeight = combinedWorkArea.bottom - combinedWorkArea.top; + monitorJson.monitorWidth = combinedMonitorArea.right - combinedMonitorArea.left; monitorJson.monitorHeight = combinedMonitorArea.bottom - combinedMonitorArea.top; monitorJson.isSelected = true; @@ -133,8 +154,6 @@ bool EditorParameters::Save() noexcept } else { - auto monitors = MonitorUtils::IdentifyMonitors(); - HMONITOR targetMonitor{}; if (FancyZonesSettings::settings().use_cursorpos_editor_startupscreen) { @@ -153,10 +172,25 @@ bool EditorParameters::Save() noexcept return false; } - for (auto& monitorData : monitors) + const auto& config = configuration.GetAllWorkAreas(); + for (auto& [monitor, workArea] : config) { - HMONITOR monitor = monitorData.monitor; + JsonUtils::MonitorInfo monitorJson; + if (!monitorJson.FillFromWorkArea(workArea.get())) + { + continue; + } + monitorJson.isSelected = monitor == targetMonitor; /* Is monitor selected for the main editor window opening */ + + UINT dpi = 0; + if (DPIAware::GetScreenDPIForMonitor(monitor, dpi) != S_OK) + { + continue; + } + + monitorJson.dpi = dpi; + MONITORINFOEX monitorInfo{}; dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] { monitorInfo.cbSize = sizeof(monitorInfo); @@ -166,31 +200,6 @@ bool EditorParameters::Save() noexcept } } }).wait(); - JsonUtils::MonitorInfo monitorJson; - - if (monitor == targetMonitor) - { - monitorJson.isSelected = true; /* Is monitor selected for the main editor window opening */ - } - - monitorJson.monitorName = monitorData.deviceId.id; - monitorJson.monitorInstanceId = monitorData.deviceId.instanceId; - monitorJson.monitorNumber = monitorData.deviceId.number; - monitorJson.monitorSerialNumber = monitorData.serialNumber; - monitorJson.virtualDesktop = virtualDesktopIdStr.value(); - - UINT dpi = 0; - if (DPIAware::GetScreenDPIForMonitor(monitor, dpi) != S_OK) - { - continue; - } - - monitorJson.dpi = dpi; - monitorJson.top = monitorInfo.rcWork.top; - monitorJson.left = monitorInfo.rcWork.left; - monitorJson.workAreaWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left; - monitorJson.workAreaHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; - float width = static_cast(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left); float height = static_cast(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); DPIAware::Convert(monitor, width, height); @@ -198,6 +207,12 @@ bool EditorParameters::Save() noexcept monitorJson.monitorWidth = static_cast(std::roundf(width)); monitorJson.monitorHeight = static_cast(std::roundf(height)); + // use dpi-unaware values + monitorJson.top = monitorInfo.rcWork.top; + monitorJson.left = monitorInfo.rcWork.left; + monitorJson.workAreaWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left; + monitorJson.workAreaHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; + argsJson.monitors.emplace_back(std::move(monitorJson)); } } diff --git a/src/modules/fancyzones/FancyZonesLib/EditorParameters.h b/src/modules/fancyzones/FancyZonesLib/EditorParameters.h index 70124613d6..74415e9c28 100644 --- a/src/modules/fancyzones/FancyZonesLib/EditorParameters.h +++ b/src/modules/fancyzones/FancyZonesLib/EditorParameters.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + namespace NonLocalizable { namespace EditorParametersIds @@ -26,5 +29,5 @@ namespace NonLocalizable class EditorParameters { public: - static bool Save() noexcept; + static bool Save(const WorkAreaConfiguration& configuration, OnThreadExecutor& dpiUnawareThread) noexcept; }; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index 7ddcd955c5..d2314d7816 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -15,13 +15,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -30,6 +30,7 @@ #include #include #include +#include enum class DisplayChangeType { @@ -88,6 +89,7 @@ public: AppliedLayouts::instance().LoadData(); AppZoneHistory::instance().LoadData(); DefaultLayouts::instance().LoadData(); + LastUsedVirtualDesktop::instance().LoadData(); } // IFancyZones @@ -170,7 +172,7 @@ private: HWND m_window{}; std::unique_ptr m_windowMouseSnapper{}; WindowKeyboardSnap m_windowKeyboardSnapper{}; - MonitorWorkAreaMap m_workAreaHandler; + WorkAreaConfiguration m_workAreaConfiguration; DraggingState m_draggingState; wil::unique_handle m_terminateEditorEvent; // Handle of FancyZonesEditor.exe we launch and wait on @@ -254,6 +256,7 @@ FancyZones::Run() noexcept } }); + VirtualDesktop::instance().UpdateVirtualDesktopId(); SyncVirtualDesktops(); // id format of applied-layouts and app-zone-history was changed in 0.60 @@ -268,7 +271,7 @@ FancyZones::Run() noexcept IFACEMETHODIMP_(void) FancyZones::Destroy() noexcept { - m_workAreaHandler.Clear(); + m_workAreaConfiguration.Clear(); BufferedPaintUnInit(); if (m_window) { @@ -290,7 +293,7 @@ FancyZones::VirtualDesktopChanged() noexcept void FancyZones::MoveSizeStart(HWND window, HMONITOR monitor) { - m_windowMouseSnapper = WindowMouseSnap::Create(window, m_workAreaHandler.GetAllWorkAreas()); + m_windowMouseSnapper = WindowMouseSnap::Create(window, m_workAreaConfiguration.GetAllWorkAreas()); if (m_windowMouseSnapper) { if (FancyZonesSettings::settings().spanZonesAcrossMonitors) @@ -330,7 +333,7 @@ void FancyZones::MoveSizeEnd() bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept { - const auto& workAreas = m_workAreaHandler.GetAllWorkAreas(); + const auto& workAreas = m_workAreaConfiguration.GetAllWorkAreas(); WorkArea* workArea{ nullptr }; ZoneIndexSet indexes{}; @@ -518,7 +521,7 @@ void FancyZones::ToggleEditor() noexcept m_terminateEditorEvent.reset(CreateEvent(nullptr, true, false, nullptr)); - if (!EditorParameters::Save()) + if (!EditorParameters::Save(m_workAreaConfiguration, m_dpiUnawareThread)) { Logger::error(L"Failed to save editor startup parameters"); return; @@ -618,11 +621,11 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa // Check whether Alt is used in the shortcut key combination if (GetAsyncKeyState(VK_MENU) & 0x8000) { - m_windowKeyboardSnapper.Extend(foregroundWindow, windowRect, monitor, static_cast(lparam), m_workAreaHandler.GetAllWorkAreas()); + m_windowKeyboardSnapper.Extend(foregroundWindow, windowRect, monitor, static_cast(lparam), m_workAreaConfiguration.GetAllWorkAreas()); } else { - m_windowKeyboardSnapper.Snap(foregroundWindow, windowRect, monitor, static_cast(lparam), m_workAreaHandler.GetAllWorkAreas(), monitors); + m_windowKeyboardSnapper.Snap(foregroundWindow, windowRect, monitor, static_cast(lparam), m_workAreaConfiguration.GetAllWorkAreas(), monitors); } } else @@ -632,7 +635,7 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa } else { - m_windowKeyboardSnapper.Snap(foregroundWindow, monitor, static_cast(lparam), m_workAreaHandler.GetAllWorkAreas(), FancyZonesUtils::GetMonitorsOrdered()); + m_windowKeyboardSnapper.Snap(foregroundWindow, monitor, static_cast(lparam), m_workAreaConfiguration.GetAllWorkAreas(), FancyZonesUtils::GetMonitorsOrdered()); } } else if (message == WM_PRIV_INIT) @@ -727,6 +730,7 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept updateWindowsPositions = FancyZonesSettings::settings().displayChange_moveWindows; break; case DisplayChangeType::VirtualDesktop: // Switched virtual desktop + SyncVirtualDesktops(); break; case DisplayChangeType::Initialization: // Initialization updateWindowsPositions = FancyZonesSettings::settings().zoneSetChange_moveWindows; @@ -755,15 +759,18 @@ bool FancyZones::AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAr { rect = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>(); } - - auto workArea = WorkArea::Create(m_hinstance, id, m_workAreaHandler.GetParent(monitor), rect); + + auto parentWorkAreaId = id; + parentWorkAreaId.virtualDesktopId = LastUsedVirtualDesktop::instance().GetId(); + + auto workArea = WorkArea::Create(m_hinstance, id, parentWorkAreaId, rect); if (!workArea) { Logger::error(L"Failed to create work area {}", id.toString()); return false; } - m_workAreaHandler.AddWorkArea(monitor, std::move(workArea)); + m_workAreaConfiguration.AddWorkArea(monitor, std::move(workArea)); return true; } @@ -785,8 +792,7 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept { Logger::debug(L"Update work areas, update windows positions: {}", updateWindowPositions); - m_workAreaHandler.SaveParentIds(); - m_workAreaHandler.Clear(); + m_workAreaConfiguration.Clear(); if (FancyZonesSettings::settings().spanZonesAcrossMonitors) { @@ -824,7 +830,7 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept if (FancyZonesSettings::settings().spanZonesAcrossMonitors) // one work area across monitors { - const auto workArea = m_workAreaHandler.GetWorkArea(nullptr); + const auto workArea = m_workAreaConfiguration.GetWorkArea(nullptr); if (workArea) { for (const auto& [window, zones] : windowsToSnap) @@ -841,7 +847,7 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept const auto window = iter->first; const auto zones = iter->second; const auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); - const auto workAreaForMonitor = m_workAreaHandler.GetWorkArea(monitor); + const auto workAreaForMonitor = m_workAreaConfiguration.GetWorkArea(monitor); if (workAreaForMonitor && AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaForMonitor->UniqueId(), workAreaForMonitor->GetLayoutId()) == zones) { workAreaForMonitor->Snap(window, zones, false); @@ -856,7 +862,7 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept // snap rest of the windows to other work areas (in case they were moved after the monitor unplug) for (const auto& [window, zones] : windowsToSnap) { - for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas()) + for (const auto& [_, workArea] : m_workAreaConfiguration.GetAllWorkAreas()) { const auto savedIndexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workArea->UniqueId(), workArea->GetLayoutId()); if (savedIndexes == zones) @@ -869,7 +875,7 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept if (updateWindowPositions) { - for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas()) + for (const auto& [_, workArea] : m_workAreaConfiguration.GetAllWorkAreas()) { if (workArea) { @@ -884,7 +890,7 @@ void FancyZones::CycleWindows(bool reverse) noexcept auto window = GetForegroundWindow(); HMONITOR current = WorkAreaKeyFromWindow(window); - auto workArea = m_workAreaHandler.GetWorkArea(current); + auto workArea = m_workAreaConfiguration.GetWorkArea(current); if (workArea) { workArea->CycleWindows(window, reverse); @@ -893,15 +899,23 @@ void FancyZones::CycleWindows(bool reverse) noexcept void FancyZones::SyncVirtualDesktops() noexcept { + // Explorer persists current virtual desktop identifier to registry on a per session basis, + // but only after first virtual desktop switch happens. If the user hasn't switched virtual + // desktops in this session value in registry will be empty and we will use default GUID in + // that case (00000000-0000-0000-0000-000000000000). + + auto lastUsed = LastUsedVirtualDesktop::instance().GetId(); + auto current = VirtualDesktop::instance().GetCurrentVirtualDesktopId(); auto guids = VirtualDesktop::instance().GetVirtualDesktopIdsFromRegistry(); - if (guids.has_value()) + + if (current != lastUsed) { - AppZoneHistory::instance().RemoveDeletedVirtualDesktops(*guids); - AppliedLayouts::instance().RemoveDeletedVirtualDesktops(*guids); + LastUsedVirtualDesktop::instance().SetId(current); + LastUsedVirtualDesktop::instance().SaveData(); } - AppZoneHistory::instance().SyncVirtualDesktops(); - AppliedLayouts::instance().SyncVirtualDesktops(); + AppliedLayouts::instance().SyncVirtualDesktops(current, lastUsed, guids); + AppZoneHistory::instance().SyncVirtualDesktops(current, lastUsed, guids); } void FancyZones::UpdateHotkey(int hotkeyId, const PowerToysSettings::HotkeyObject& hotkeyObject, bool enable) noexcept @@ -955,7 +969,7 @@ void FancyZones::SettingsUpdate(SettingId id) break; case SettingId::SpanZonesAcrossMonitors: { - m_workAreaHandler.Clear(); + m_workAreaConfiguration.Clear(); PostMessageW(m_window, WM_PRIV_INIT, NULL, NULL); } break; @@ -966,7 +980,7 @@ void FancyZones::SettingsUpdate(SettingId id) void FancyZones::RefreshLayouts() noexcept { - for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas()) + for (const auto& [_, workArea] : m_workAreaConfiguration.GetAllWorkAreas()) { if (workArea) { @@ -993,7 +1007,7 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept { HMONITOR monitor = WorkAreaKeyFromWindow(window); - auto workArea = m_workAreaHandler.GetWorkArea(monitor); + auto workArea = m_workAreaConfiguration.GetWorkArea(monitor); if (!workArea) { Logger::error(L"No work area for processing snap hotkey"); @@ -1038,13 +1052,15 @@ void FancyZones::ApplyQuickLayout(int key) noexcept return; } - auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(); + auto workArea = m_workAreaConfiguration.GetWorkAreaFromCursor(); if (workArea) { - AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), layout.value()); - AppliedLayouts::instance().SaveData(); - RefreshLayouts(); - FlashZones(); + if (AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), layout.value())) + { + RefreshLayouts(); + FlashZones(); + AppliedLayouts::instance().SaveData(); + } } } @@ -1052,7 +1068,7 @@ void FancyZones::FlashZones() noexcept { if (FancyZonesSettings::settings().flashZonesOnQuickSwitch && !m_draggingState.IsDragging()) { - for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas()) + for (const auto& [_, workArea] : m_workAreaConfiguration.GetAllWorkAreas()) { if (workArea) { diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h index 565abb3194..db7fe004a9 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData.h @@ -26,13 +26,7 @@ public: return settingsFileName; } -private: #if defined(UNIT_TESTS) - friend class FancyZonesUnitTests::LayoutHotkeysUnitTests; - friend class FancyZonesUnitTests::LayoutTemplatesUnitTests; - friend class FancyZonesUnitTests::CustomLayoutsUnitTests; - friend class FancyZonesUnitTests::AppliedLayoutsUnitTests; - inline void SetSettingsModulePath(std::wstring_view moduleName) { std::wstring result = PTSettingsHelper::get_module_save_folder_location(moduleName); @@ -46,6 +40,8 @@ private: return result + L"\\" + std::wstring(L"zones-settings.json"); } #endif + +private: std::wstring settingsFileName; std::wstring zonesSettingsFileName; std::wstring appZoneHistoryFileName; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp index 886dec5a84..c633f0c0f7 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp @@ -591,67 +591,43 @@ ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZone return {}; } -void AppZoneHistory::SyncVirtualDesktops() +void AppZoneHistory::SyncVirtualDesktops(const GUID& currentVirtualDesktop, const GUID& lastUsedVirtualDesktop, std::optional> desktops) { - // Explorer persists current virtual desktop identifier to registry on a per session basis, - // but only after first virtual desktop switch happens. If the user hasn't switched virtual - // desktops in this session value in registry will be empty and we will use default GUID in - // that case (00000000-0000-0000-0000-000000000000). - - auto savedInRegistryVirtualDesktopID = VirtualDesktop::instance().GetCurrentVirtualDesktopIdFromRegistry(); - if (!savedInRegistryVirtualDesktopID.has_value() || savedInRegistryVirtualDesktopID.value() == GUID_NULL) + TAppZoneHistoryMap history; + + std::unordered_set activeDesktops{}; + if (desktops.has_value()) { - return; + activeDesktops = std::unordered_set(std::begin(desktops.value()), std::end(desktops.value())); } - auto currentVirtualDesktopStr = FancyZonesUtils::GuidToString(savedInRegistryVirtualDesktopID.value()); - if (!currentVirtualDesktopStr.has_value()) - { - Logger::error(L"Failed to convert virtual desktop GUID to string"); - return; - } - - Logger::info(L"AppZoneHistory Sync virtual desktops: current {}", currentVirtualDesktopStr.value()); - - bool dirtyFlag = false; - - for (auto& [path, perDesktopData] : m_history) - { - for (auto& data : perDesktopData) + auto findCurrentVirtualDesktopInSavedHistory = [&](const std::pair>& val) -> bool + { + for (auto& data : val.second) { - if (data.workAreaId.virtualDesktopId == GUID_NULL) + if (data.workAreaId.virtualDesktopId == currentVirtualDesktop) { - data.workAreaId.virtualDesktopId = savedInRegistryVirtualDesktopID.value(); - dirtyFlag = true; + return true; } } - } + return false; + }; + bool replaceLastUsedWithCurrent = !desktops.has_value() || currentVirtualDesktop == GUID_NULL || lastUsedVirtualDesktop == GUID_NULL || std::find_if(m_history.begin(), m_history.end(), findCurrentVirtualDesktopInSavedHistory) == m_history.end(); - if (dirtyFlag) - { - Logger::info(L"Update Virtual Desktop id to {}", currentVirtualDesktopStr.value()); - SaveData(); - } -} - -void AppZoneHistory::RemoveDeletedVirtualDesktops(const std::vector& activeDesktops) -{ - std::unordered_set active(std::begin(activeDesktops), std::end(activeDesktops)); bool dirtyFlag = false; - 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->workAreaId.virtualDesktopId != GUID_NULL && !active.contains(desktopIt->workAreaId.virtualDesktopId)) + if (replaceLastUsedWithCurrent && desktopIt->workAreaId.virtualDesktopId == lastUsedVirtualDesktop) { - auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(desktopIt->workAreaId.virtualDesktopId); - if (virtualDesktopIdStr) - { - Logger::info(L"Remove Virtual Desktop id {} from app-zone-history", virtualDesktopIdStr.value()); - } + desktopIt->workAreaId.virtualDesktopId = currentVirtualDesktop; + dirtyFlag = true; + } + if (desktopIt->workAreaId.virtualDesktopId != currentVirtualDesktop && !activeDesktops.contains(desktopIt->workAreaId.virtualDesktopId)) + { desktopIt = perDesktopData.erase(desktopIt); dirtyFlag = true; } @@ -664,6 +640,7 @@ void AppZoneHistory::RemoveDeletedVirtualDesktops(const std::vector& activ if (perDesktopData.empty()) { it = m_history.erase(it); + dirtyFlag = true; } else { diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.h index 18ec84ac93..6356ab50fa 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.h @@ -41,6 +41,13 @@ public: #endif } +#if defined(UNIT_TESTS) + inline void SetAppZoneHistory(const TAppZoneHistoryMap& history) + { + m_history = history; + } +#endif + void LoadData(); void SaveData(); void AdjustWorkAreaIds(const std::vector& ids); @@ -56,9 +63,8 @@ public: bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept; ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const GUID& layoutId) const; - void SyncVirtualDesktops(); - void RemoveDeletedVirtualDesktops(const std::vector& activeDesktops); - + void SyncVirtualDesktops(const GUID& currentVirtualDesktop, const GUID& lastUsedVirtualDesktop, std::optional> desktops); + private: AppZoneHistory(); ~AppZoneHistory() = default; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppliedLayouts.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppliedLayouts.cpp index a6c86952d6..b05cd3da0b 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppliedLayouts.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppliedLayouts.cpp @@ -279,29 +279,7 @@ void AppliedLayouts::LoadData() void AppliedLayouts::SaveData() { - bool dirtyFlag = false; - TAppliedLayoutsMap updatedMap; - - for (const auto& [id, data] : m_layouts) - { - auto updatedId = id; - if (!VirtualDesktop::instance().IsVirtualDesktopIdSavedInRegistry(id.virtualDesktopId)) - { - updatedId.virtualDesktopId = GUID_NULL; - dirtyFlag = true; - } - - updatedMap.insert({ updatedId, data }); - } - - if (dirtyFlag) - { - json::to_file(AppliedLayoutsFileName(), JsonUtils::SerializeJson(updatedMap)); - } - else - { - json::to_file(AppliedLayoutsFileName(), JsonUtils::SerializeJson(m_layouts)); - } + json::to_file(AppliedLayoutsFileName(), JsonUtils::SerializeJson(m_layouts)); } void AppliedLayouts::AdjustWorkAreaIds(const std::vector& ids) @@ -344,86 +322,75 @@ void AppliedLayouts::AdjustWorkAreaIds(const std::vector> desktops) { - // Explorer persists current virtual desktop identifier to registry on a per session basis, - // but only after first virtual desktop switch happens. If the user hasn't switched virtual - // desktops in this session value in registry will be empty and we will use default GUID in - // that case (00000000-0000-0000-0000-000000000000). + TAppliedLayoutsMap layouts; - auto savedInRegistryVirtualDesktopID = VirtualDesktop::instance().GetCurrentVirtualDesktopIdFromRegistry(); - if (!savedInRegistryVirtualDesktopID.has_value() || savedInRegistryVirtualDesktopID.value() == GUID_NULL) + auto findCurrentVirtualDesktopInSavedLayouts = [&](const std::pair& val) -> bool { return val.first.virtualDesktopId == currentVirtualDesktop; }; + bool replaceLastUsedWithCurrent = !desktops.has_value() || currentVirtualDesktop == GUID_NULL || + std::find_if(m_layouts.begin(), m_layouts.end(), findCurrentVirtualDesktopInSavedLayouts) == m_layouts.end(); + bool copyToOtherVirtualDesktops = lastUsedVirtualDesktop == GUID_NULL && currentVirtualDesktop != GUID_NULL && desktops.has_value(); + + for (const auto& [workAreaId, layout] : m_layouts) { - return; - } - - auto currentVirtualDesktopStr = FancyZonesUtils::GuidToString(savedInRegistryVirtualDesktopID.value()); - if (!currentVirtualDesktopStr.has_value()) - { - Logger::error(L"Failed to convert virtual desktop GUID to string"); - return; - } - - Logger::info(L"AppliedLayouts Sync virtual desktops: current {}", currentVirtualDesktopStr.value()); - - bool dirtyFlag = false; - - std::vector replaceWithCurrentId{}; - - for (const auto& [id, data] : m_layouts) - { - if (id.virtualDesktopId == GUID_NULL) + if (replaceLastUsedWithCurrent && workAreaId.virtualDesktopId == lastUsedVirtualDesktop) { - replaceWithCurrentId.push_back(id); - dirtyFlag = true; - } - } + // replace "lastUsedVirtualDesktop" with "currentVirtualDesktop" + auto updatedWorkAreaId = workAreaId; + updatedWorkAreaId.virtualDesktopId = currentVirtualDesktop; + layouts.insert({ updatedWorkAreaId, layout }); - for (const auto& id : replaceWithCurrentId) - { - auto mapEntry = m_layouts.extract(id); - mapEntry.key().virtualDesktopId = savedInRegistryVirtualDesktopID.value(); - m_layouts.insert(std::move(mapEntry)); - } - - if (dirtyFlag) - { - Logger::info(L"Update Virtual Desktop id to {}", currentVirtualDesktopStr.value()); - SaveData(); - } -} - -void AppliedLayouts::RemoveDeletedVirtualDesktops(const std::vector& activeDesktops) -{ - std::unordered_set active(std::begin(activeDesktops), std::end(activeDesktops)); - bool dirtyFlag = false; - - for (auto it = std::begin(m_layouts); it != std::end(m_layouts);) - { - GUID desktopId = it->first.virtualDesktopId; - - if (desktopId != GUID_NULL) - { - auto foundId = active.find(desktopId); - if (foundId == std::end(active)) + if (copyToOtherVirtualDesktops) { - wil::unique_cotaskmem_string virtualDesktopIdStr; - if (SUCCEEDED(StringFromCLSID(desktopId, &virtualDesktopIdStr))) + // Copy to other virtual desktops on the 1st VD creation. + // If we just replace the id, we'll lose the layout on the other desktops. + // Usage scenario: + // apply the layout to the single virtual desktop with id = GUID_NULL, + // create the 2nd virtual desktop and switch to it, + // so virtual desktop id changes from GUID_NULL to a valid value of the 2nd VD. + // Then change the layout on the 2nd VD and switch back to the 1st VD. + // Layout on the initial VD will be changed too without initializing it beforehand. + for (const auto& id : desktops.value()) { - Logger::info(L"Remove Virtual Desktop id {}", virtualDesktopIdStr.get()); + if (id != currentVirtualDesktop) + { + auto copyWorkAreaId = workAreaId; + copyWorkAreaId.virtualDesktopId = id; + layouts.insert({ copyWorkAreaId, layout }); + } } - - it = m_layouts.erase(it); - dirtyFlag = true; - continue; } } - ++it; + + if (workAreaId.virtualDesktopId == currentVirtualDesktop || (desktops.has_value() && + std::find(desktops.value().begin(), desktops.value().end(), workAreaId.virtualDesktopId) != desktops.value().end())) + { + // keep only actual virtual desktop values + layouts.insert({ workAreaId, layout }); + } } - if (dirtyFlag) + if (layouts != m_layouts) { + m_layouts = layouts; SaveData(); + + std::wstring currentStr = FancyZonesUtils::GuidToString(currentVirtualDesktop).value_or(L"incorrect guid"); + std::wstring lastUsedStr = FancyZonesUtils::GuidToString(lastUsedVirtualDesktop).value_or(L"incorrect guid"); + std::wstring registryStr{}; + if (desktops.has_value()) + { + for (const auto& id : desktops.value()) + { + registryStr += FancyZonesUtils::GuidToString(id).value_or(L"incorrect guid") + L" "; + } + } + else + { + registryStr = L"empty"; + } + + Logger::info(L"Synced virtual desktops. Current: {}, last used: {}, registry: {}", currentStr, lastUsedStr, registryStr); } } @@ -449,9 +416,9 @@ bool AppliedLayouts::IsLayoutApplied(const FancyZonesDataTypes::WorkAreaId& id) return iter != m_layouts.end(); } -bool AppliedLayouts::ApplyLayout(const FancyZonesDataTypes::WorkAreaId& deviceId, LayoutData layout) +bool AppliedLayouts::ApplyLayout(const FancyZonesDataTypes::WorkAreaId& workAreaId, LayoutData layout) { - m_layouts[deviceId] = std::move(layout); + m_layouts[workAreaId] = layout; return true; } @@ -496,9 +463,5 @@ bool AppliedLayouts::CloneLayout(const FancyZonesDataTypes::WorkAreaId& srcId, c } Logger::info(L"Clone layout from {} to {}", dstId.toString(), srcId.toString()); - m_layouts[dstId] = m_layouts[srcId]; - - SaveData(); - - return true; + return ApplyLayout(dstId, m_layouts[srcId]); } diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppliedLayouts.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppliedLayouts.h index bea37c6d92..e4f796913b 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppliedLayouts.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppliedLayouts.h @@ -49,12 +49,18 @@ public: #endif } +#if defined(UNIT_TESTS) + inline void SetAppliedLayouts(TAppliedLayoutsMap layouts) + { + m_layouts = layouts; + } +#endif + void LoadData(); void SaveData(); void AdjustWorkAreaIds(const std::vector& ids); - void SyncVirtualDesktops(); - void RemoveDeletedVirtualDesktops(const std::vector& activeDesktops); + void SyncVirtualDesktops(const GUID& currentVirtualDesktop, const GUID& lastUsedVirtualDesktop, std::optional> desktops); std::optional GetDeviceLayout(const FancyZonesDataTypes::WorkAreaId& id) const noexcept; const TAppliedLayoutsMap& GetAppliedLayoutMap() const noexcept; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/LastUsedVirtualDesktop.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/LastUsedVirtualDesktop.cpp new file mode 100644 index 0000000000..3c62df9e88 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/LastUsedVirtualDesktop.cpp @@ -0,0 +1,78 @@ +#include "../pch.h" +#include "LastUsedVirtualDesktop.h" + +#include + +#include + +namespace JsonUtils +{ + GUID ParseJson(const json::JsonObject& json) + { + auto idStr = json.GetNamedString(NonLocalizable::LastUsedVirtualDesktop::LastUsedVirtualDesktopID); + auto idOpt = FancyZonesUtils::GuidFromString(idStr.c_str()); + + if (!idOpt.has_value()) + { + return {}; + } + + return idOpt.value(); + } + + json::JsonObject SerializeJson(const GUID& id) + { + json::JsonObject result{}; + + auto virtualDesktopStr = FancyZonesUtils::GuidToString(id); + if (virtualDesktopStr) + { + result.SetNamedValue(NonLocalizable::LastUsedVirtualDesktop::LastUsedVirtualDesktopID, json::value(virtualDesktopStr.value())); + } + + return result; + } +} + + +LastUsedVirtualDesktop& LastUsedVirtualDesktop::instance() +{ + static LastUsedVirtualDesktop self; + return self; +} + +void LastUsedVirtualDesktop::LoadData() +{ + auto data = json::from_file(LastUsedVirtualDesktopFileName()); + + try + { + if (data) + { + m_id = JsonUtils::ParseJson(data.value()); + } + else + { + m_id = GUID_NULL; + } + } + catch (const winrt::hresult_error& e) + { + Logger::error(L"Parsing last-used-virtual-desktop error: {}", e.message()); + } +} + +void LastUsedVirtualDesktop::SaveData() const +{ + json::to_file(LastUsedVirtualDesktopFileName(), JsonUtils::SerializeJson(m_id)); +} + +GUID LastUsedVirtualDesktop::GetId() const +{ + return m_id; +} + +void LastUsedVirtualDesktop::SetId(GUID id) +{ + m_id = id; +} \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/LastUsedVirtualDesktop.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/LastUsedVirtualDesktop.h new file mode 100644 index 0000000000..da9e07eca4 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/LastUsedVirtualDesktop.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include + +namespace NonLocalizable +{ + namespace LastUsedVirtualDesktop + { + const static wchar_t* LastUsedVirtualDesktopID = L"last-used-virtual-desktop"; + } +} + +class LastUsedVirtualDesktop +{ +public: + static LastUsedVirtualDesktop& instance(); + + inline static std::wstring LastUsedVirtualDesktopFileName() + { + std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey); +#if defined(UNIT_TESTS) + return saveFolderPath + L"\\test-last-used-virtual-desktop.json"; +#else + return saveFolderPath + L"\\last-used-virtual-desktop.json"; +#endif + } + + void LoadData(); + void SaveData() const; + + GUID GetId() const; + void SetId(GUID id); + +private: + LastUsedVirtualDesktop() = default; + ~LastUsedVirtualDesktop() = default; + + GUID m_id{}; +}; diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesDataTypes.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesDataTypes.h index 6f61b3e125..58673c7012 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesDataTypes.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesDataTypes.h @@ -209,14 +209,12 @@ namespace FancyZonesDataTypes inline bool operator==(const WorkAreaId& lhs, const WorkAreaId& rhs) { - bool vdEqual = (lhs.virtualDesktopId == rhs.virtualDesktopId || lhs.virtualDesktopId == GUID_NULL || rhs.virtualDesktopId == GUID_NULL); - return vdEqual && lhs.monitorId == rhs.monitorId; + return lhs.virtualDesktopId == rhs.virtualDesktopId && lhs.monitorId == rhs.monitorId; } inline bool operator!=(const WorkAreaId& lhs, const WorkAreaId& rhs) { - bool vdEqual = (lhs.virtualDesktopId == rhs.virtualDesktopId || lhs.virtualDesktopId == GUID_NULL || rhs.virtualDesktopId == GUID_NULL); - return !vdEqual || lhs.monitorId != rhs.monitorId; + return lhs.virtualDesktopId != rhs.virtualDesktopId || lhs.monitorId != rhs.monitorId; } inline bool operator<(const WorkAreaId& lhs, const WorkAreaId& rhs) @@ -240,6 +238,11 @@ namespace FancyZonesDataTypes return lhs.monitorId.deviceId < rhs.monitorId.deviceId; } + + inline bool operator==(const AppZoneHistoryData& lhs, const AppZoneHistoryData& rhs) + { + return lhs.layoutId == rhs.layoutId && lhs.workAreaId == rhs.workAreaId && lhs.zoneIndexSet == rhs.zoneIndexSet && lhs.processIdToHandleMap == rhs.processIdToHandleMap; + } } namespace std diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj index a659a1839e..faf124b3ef 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj @@ -43,6 +43,7 @@ + @@ -59,7 +60,7 @@ - + @@ -100,6 +101,9 @@ ../pch.h + + ../pch.h + ../pch.h @@ -115,7 +119,7 @@ - + Create diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters index f97b95c5a9..220b0cc22f 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters @@ -54,7 +54,7 @@ Header Files - + Header Files @@ -168,6 +168,9 @@ Header Files + + Header Files\FancyZonesData + @@ -200,7 +203,7 @@ Source Files - + Source Files @@ -272,6 +275,9 @@ Source Files + + Source Files\FancyZonesData + Source Files diff --git a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp index 67bf726d2b..dbd1511d5a 100644 --- a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp +++ b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp @@ -270,30 +270,16 @@ GUID VirtualDesktop::GetCurrentVirtualDesktopId() const noexcept return m_currentVirtualDesktopId; } -GUID VirtualDesktop::GetPreviousVirtualDesktopId() const noexcept -{ - return m_previousDesktopId; -} - void VirtualDesktop::UpdateVirtualDesktopId() noexcept { - m_previousDesktopId = m_currentVirtualDesktopId; - auto currentVirtualDesktopId = GetCurrentVirtualDesktopIdFromRegistry(); - if (!currentVirtualDesktopId.has_value()) - { - Logger::info("No Virtual Desktop Id found in registry"); - currentVirtualDesktopId = VirtualDesktop::instance().GetDesktopIdByTopLevelWindows(); - } - if (currentVirtualDesktopId.has_value()) { - m_currentVirtualDesktopId = *currentVirtualDesktopId; - - if (m_currentVirtualDesktopId == GUID_NULL) - { - Logger::warn("Couldn't retrieve virtual desktop id"); - } + m_currentVirtualDesktopId = currentVirtualDesktopId.value(); + } + else + { + m_currentVirtualDesktopId = GUID_NULL; } Trace::VirtualDesktopChanged(); diff --git a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h index 069e1883ea..4c25518ce8 100644 --- a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h +++ b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h @@ -7,7 +7,6 @@ public: // saved values GUID GetCurrentVirtualDesktopId() const noexcept; - GUID GetPreviousVirtualDesktopId() const noexcept; void UpdateVirtualDesktopId() noexcept; // IVirtualDesktopManager @@ -29,7 +28,6 @@ private: IVirtualDesktopManager* m_vdManager{nullptr}; GUID m_currentVirtualDesktopId{}; - GUID m_previousDesktopId{}; std::optional> GetVirtualDesktopIdsFromRegistry(HKEY hKey) const; }; diff --git a/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp b/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp index 2d4b6adf90..638776c25a 100644 --- a/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp @@ -244,14 +244,12 @@ void WorkArea::InitLayout(const FancyZonesDataTypes::WorkAreaId& parentUniqueId) const bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId); if (!isLayoutAlreadyApplied) { - if (parentUniqueId.virtualDesktopId != GUID_NULL) - { - AppliedLayouts::instance().CloneLayout(parentUniqueId, m_uniqueId); - } - else + if (!AppliedLayouts::instance().CloneLayout(parentUniqueId, m_uniqueId)) { AppliedLayouts::instance().ApplyDefaultLayout(m_uniqueId); } + + AppliedLayouts::instance().SaveData(); } CalculateZoneSet(); diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.cpp b/src/modules/fancyzones/FancyZonesLib/WorkAreaConfiguration.cpp similarity index 57% rename from src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.cpp rename to src/modules/fancyzones/FancyZonesLib/WorkAreaConfiguration.cpp index 486e2739ea..a3cfa7cf45 100644 --- a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WorkAreaConfiguration.cpp @@ -1,9 +1,9 @@ #include "pch.h" -#include "MonitorWorkAreaMap.h" +#include "WorkAreaConfiguration.h" #include -WorkArea* const MonitorWorkAreaMap::GetWorkArea(HMONITOR monitor) const +WorkArea* const WorkAreaConfiguration::GetWorkArea(HMONITOR monitor) const { auto iter = m_workAreaMap.find(monitor); if (iter != m_workAreaMap.end()) @@ -14,7 +14,7 @@ WorkArea* const MonitorWorkAreaMap::GetWorkArea(HMONITOR monitor) const return nullptr; } -WorkArea* const MonitorWorkAreaMap::GetWorkAreaFromCursor() const +WorkArea* const WorkAreaConfiguration::GetWorkAreaFromCursor() const { const auto allMonitorsWorkArea = GetWorkArea(nullptr); if (allMonitorsWorkArea) @@ -35,7 +35,7 @@ WorkArea* const MonitorWorkAreaMap::GetWorkAreaFromCursor() const } } -WorkArea* const MonitorWorkAreaMap::GetWorkAreaFromWindow(HWND window) const +WorkArea* const WorkAreaConfiguration::GetWorkAreaFromWindow(HWND window) const { const auto allMonitorsWorkArea = GetWorkArea(nullptr); if (allMonitorsWorkArea) @@ -51,39 +51,17 @@ WorkArea* const MonitorWorkAreaMap::GetWorkAreaFromWindow(HWND window) const } } -const std::unordered_map>& MonitorWorkAreaMap::GetAllWorkAreas() const noexcept +const std::unordered_map>& WorkAreaConfiguration::GetAllWorkAreas() const noexcept { return m_workAreaMap; } -void MonitorWorkAreaMap::AddWorkArea(HMONITOR monitor, std::unique_ptr workArea) +void WorkAreaConfiguration::AddWorkArea(HMONITOR monitor, std::unique_ptr workArea) { m_workAreaMap.insert({ monitor, std::move(workArea) }); } -FancyZonesDataTypes::WorkAreaId MonitorWorkAreaMap::GetParent(HMONITOR monitor) const -{ - if (m_workAreaParents.contains(monitor)) - { - return m_workAreaParents.at(monitor); - } - - return FancyZonesDataTypes::WorkAreaId{}; -} - -void MonitorWorkAreaMap::SaveParentIds() -{ - m_workAreaParents.clear(); - for (const auto& [monitor, workArea] : m_workAreaMap) - { - if (workArea) - { - m_workAreaParents.insert({ monitor, workArea->UniqueId() }); - } - } -} - -void MonitorWorkAreaMap::Clear() noexcept +void WorkAreaConfiguration::Clear() noexcept { m_workAreaMap.clear(); } diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.h b/src/modules/fancyzones/FancyZonesLib/WorkAreaConfiguration.h similarity index 78% rename from src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.h rename to src/modules/fancyzones/FancyZonesLib/WorkAreaConfiguration.h index 45fabda709..9530dbdae3 100644 --- a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.h +++ b/src/modules/fancyzones/FancyZonesLib/WorkAreaConfiguration.h @@ -1,15 +1,14 @@ #pragma once -#include "GuidUtils.h" #include class WorkArea; -class MonitorWorkAreaMap +class WorkAreaConfiguration { public: /** - * Get work area based on virtual desktop id and monitor handle. + * Get work area based on monitor handle. * * @param[in] monitor Monitor handle. * @@ -19,7 +18,7 @@ public: WorkArea* const GetWorkArea(HMONITOR monitor) const; /** - * Get work area based on virtual desktop id and the current cursor position. + * Get work area based on the current cursor position. * * @returns Object representing single work area, interface to all actions available on work area * (e.g. moving windows through zone layout specified for that work area). @@ -49,13 +48,6 @@ public: */ void AddWorkArea(HMONITOR monitor, std::unique_ptr workArea); - FancyZonesDataTypes::WorkAreaId GetParent(HMONITOR monitor) const; - - /** - * Saving current work area IDs as parents for later use. - */ - void SaveParentIds(); - /** * Clear all persisted work area related data. */ @@ -63,5 +55,4 @@ public: private: std::unordered_map> m_workAreaMap; - std::unordered_map m_workAreaParents{}; }; diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/AppZoneHistoryTests.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/AppZoneHistoryTests.Spec.cpp index c3e954fb00..c3eea23236 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/AppZoneHistoryTests.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/AppZoneHistoryTests.Spec.cpp @@ -339,4 +339,159 @@ namespace FancyZonesUnitTests Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(nullptr, workAreaId, layoutId)); } }; + + TEST_CLASS (AppZoneHistorySyncVirtualDesktops) + { + const GUID virtualDesktop1 = FancyZonesUtils::GuidFromString(L"{30387C86-BB15-476D-8683-AF93F6D73E99}").value(); + const GUID virtualDesktop2 = FancyZonesUtils::GuidFromString(L"{65F6343A-868F-47EE-838E-55A178A7FB7A}").value(); + const GUID deletedVirtualDesktop = FancyZonesUtils::GuidFromString(L"{2D9F3E2D-F61D-4618-B35D-85C9B8DFDFD8}").value(); + + FancyZonesDataTypes::WorkAreaId GetWorkAreaID(GUID virtualDesktop) + { + return FancyZonesDataTypes::WorkAreaId{ + .monitorId = { + .deviceId = { .id = L"id", .instanceId = L"id", .number = 1 }, + .serialNumber = L"serial-number" + }, + .virtualDesktopId = virtualDesktop + }; + } + + FancyZonesDataTypes::AppZoneHistoryData GetAppZoneHistoryData(GUID virtualDesktop, const std::wstring& layoutId, const ZoneIndexSet& zones) + { + return FancyZonesDataTypes::AppZoneHistoryData{ + .layoutId = FancyZonesUtils::GuidFromString(layoutId).value(), + .workAreaId = GetWorkAreaID(virtualDesktop), + .zoneIndexSet = zones + }; + }; + + TEST_METHOD_INITIALIZE(Init) + { + AppZoneHistory::instance().LoadData(); + } + + TEST_METHOD_CLEANUP(CleanUp) + { + std::filesystem::remove(AppZoneHistory::AppZoneHistoryFileName()); + } + + TEST_METHOD (SyncVirtualDesktops_SwitchVirtualDesktop) + { + AppZoneHistory::TAppZoneHistoryMap history{}; + const std::wstring app = L"app"; + history.insert({ app, std::vector{ + GetAppZoneHistoryData(virtualDesktop1, L"{147243D0-1111-4225-BCD3-31029FE384FC}", { 0 }), + GetAppZoneHistoryData(virtualDesktop2, L"{EAC1BB3B-13D6-4839-BBF7-58C3E8AB7229}", { 1 }), + } }); + AppZoneHistory::instance().SetAppZoneHistory(history); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = virtualDesktop2; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1, virtualDesktop2 } }; + AppZoneHistory::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(history.at(app)[0] == AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(virtualDesktop1)).value()); + Assert::IsTrue(history.at(app)[1] == AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(virtualDesktop2)).value()); + } + + TEST_METHOD (SyncVirtualDesktops_CurrentVirtualDesktopDeleted) + { + AppZoneHistory::TAppZoneHistoryMap history{}; + const std::wstring app = L"app"; + history.insert({ app, std::vector{ + GetAppZoneHistoryData(virtualDesktop1, L"{147243D0-1111-4225-BCD3-31029FE384FC}", { 0 }), + GetAppZoneHistoryData(deletedVirtualDesktop, L"{EAC1BB3B-13D6-4839-BBF7-58C3E8AB7229}", { 1 }), + } }); + AppZoneHistory::instance().SetAppZoneHistory(history); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = deletedVirtualDesktop; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1 } }; + AppZoneHistory::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(history.at(app)[0] == AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(virtualDesktop1)).value()); + Assert::IsFalse(AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(deletedVirtualDesktop)).has_value()); + } + + TEST_METHOD (SyncVirtualDesktops_NotCurrentVirtualDesktopDeleted) + { + AppZoneHistory::TAppZoneHistoryMap history{}; + const std::wstring app = L"app"; + history.insert({ app, std::vector{ + GetAppZoneHistoryData(virtualDesktop1, L"{147243D0-1111-4225-BCD3-31029FE384FC}", { 0 }), + GetAppZoneHistoryData(deletedVirtualDesktop, L"{EAC1BB3B-13D6-4839-BBF7-58C3E8AB7229}", { 1 }), + } }); + AppZoneHistory::instance().SetAppZoneHistory(history); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = virtualDesktop1; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1 } }; + AppZoneHistory::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(history.at(app)[0] == AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(virtualDesktop1)).value()); + Assert::IsFalse(AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(deletedVirtualDesktop)).has_value()); + } + + TEST_METHOD (SyncVirtualDesktops_AllIdsFromRegistryAreNew) + { + AppZoneHistory::TAppZoneHistoryMap history{}; + const std::wstring app = L"app"; + history.insert({ app, std::vector{ + GetAppZoneHistoryData(deletedVirtualDesktop, L"{147243D0-1111-4225-BCD3-31029FE384FC}", { 0 }), + } }); + AppZoneHistory::instance().SetAppZoneHistory(history); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = deletedVirtualDesktop; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1, virtualDesktop2 } }; + AppZoneHistory::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + auto expected = history.at(app)[0]; + expected.workAreaId.virtualDesktopId = currentVirtualDesktop; + Assert::IsTrue(expected == AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(virtualDesktop1)).value()); + Assert::IsFalse(AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(virtualDesktop2)).has_value()); + Assert::IsFalse(AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(deletedVirtualDesktop)).has_value()); + } + + TEST_METHOD (SyncVirtualDesktop_NoDesktopsInRegistry) + { + AppZoneHistory::TAppZoneHistoryMap history{}; + const std::wstring app = L"app"; + history.insert({ app, std::vector{ + GetAppZoneHistoryData(deletedVirtualDesktop, L"{147243D0-1111-4225-BCD3-31029FE384FC}", { 0 }), + } }); + AppZoneHistory::instance().SetAppZoneHistory(history); + + GUID currentVirtualDesktop = GUID_NULL; + GUID lastUsedVirtualDesktop = deletedVirtualDesktop; + std::optional> virtualDesktopsInRegistry = std::nullopt; + AppZoneHistory::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + auto expected = history.at(app)[0]; + expected.workAreaId.virtualDesktopId = currentVirtualDesktop; + Assert::IsTrue(expected == AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(currentVirtualDesktop)).value()); + Assert::IsFalse(AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(deletedVirtualDesktop)).has_value()); + } + + TEST_METHOD (SyncVirtualDesktop_SwithVirtualDesktopFirstTime) + { + AppZoneHistory::TAppZoneHistoryMap history{}; + const std::wstring app = L"app"; + history.insert({ app, std::vector{ + GetAppZoneHistoryData(GUID_NULL, L"{147243D0-1111-4225-BCD3-31029FE384FC}", { 0 }), + } }); + AppZoneHistory::instance().SetAppZoneHistory(history); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = GUID_NULL; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1, virtualDesktop2 } }; + AppZoneHistory::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + auto expected = history.at(app)[0]; + expected.workAreaId.virtualDesktopId = currentVirtualDesktop; + Assert::IsTrue(expected == AppZoneHistory::instance().GetZoneHistory(app, GetWorkAreaID(currentVirtualDesktop)).value()); + } + }; + } diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/AppliedLayoutsTests.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/AppliedLayoutsTests.Spec.cpp index 87f5da5a3c..ec9256664b 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/AppliedLayoutsTests.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/AppliedLayoutsTests.Spec.cpp @@ -14,24 +14,14 @@ namespace FancyZonesUnitTests { TEST_CLASS (AppliedLayoutsUnitTests) { - FancyZonesData& m_fzData = FancyZonesDataInstance(); - std::wstring m_testFolder = L"FancyZonesUnitTests"; - std::wstring m_testFolderPath = PTSettingsHelper::get_module_save_folder_location(m_testFolder); - TEST_METHOD_INITIALIZE(Init) { - m_fzData.SetSettingsModulePath(L"FancyZonesUnitTests"); + AppliedLayouts::instance().LoadData(); } TEST_METHOD_CLEANUP(CleanUp) { - // Move...FromZonesSettings creates all of these files, clean up - std::filesystem::remove(AppliedLayouts::AppliedLayoutsFileName()); - std::filesystem::remove(CustomLayouts::CustomLayoutsFileName()); - std::filesystem::remove(LayoutHotkeys::LayoutHotkeysFileName()); - std::filesystem::remove(LayoutTemplates::LayoutTemplatesFileName()); - std::filesystem::remove_all(m_testFolderPath); - AppliedLayouts::instance().LoadData(); // clean data + std::filesystem::remove(AppliedLayouts::AppliedLayoutsFileName()); } TEST_METHOD (AppliedLayoutsParse) @@ -75,7 +65,7 @@ namespace FancyZonesUnitTests Assert::IsTrue(AppliedLayouts::instance().IsLayoutApplied(id)); } - TEST_METHOD(AppliedLayoutsParseDataWithResolution) + TEST_METHOD (AppliedLayoutsParseDataWithResolution) { // prepare json::JsonObject root{}; @@ -242,143 +232,94 @@ namespace FancyZonesUnitTests Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().empty()); } - TEST_METHOD (MoveAppliedLayoutsFromZonesSettings) + TEST_METHOD (Save) { - // prepare - json::JsonObject root{}; - json::JsonArray devicesArray{}, customLayoutsArray{}, templateLayoutsArray{}, quickLayoutKeysArray{}; - - { - json::JsonObject activeZoneset{}; - activeZoneset.SetNamedValue(L"uuid", json::value(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}")); - activeZoneset.SetNamedValue(L"type", json::value(FancyZonesDataTypes::TypeToString(FancyZonesDataTypes::ZoneSetLayoutType::Rows))); - - json::JsonObject obj{}; - obj.SetNamedValue(L"device-id", json::value(L"VSC9636#5&37ac4db&0&UID160005_3840_2160_{00000000-0000-0000-0000-000000000000}")); - obj.SetNamedValue(L"active-zoneset", activeZoneset);; - obj.SetNamedValue(L"editor-show-spacing", json::value(true)); - obj.SetNamedValue(L"editor-spacing", json::value(3)); - obj.SetNamedValue(L"editor-zone-count", json::value(4)); - obj.SetNamedValue(L"editor-sensitivity-radius", json::value(22)); - - devicesArray.Append(obj); - } - - root.SetNamedValue(L"devices", devicesArray); - root.SetNamedValue(L"custom-zone-sets", customLayoutsArray); - root.SetNamedValue(L"templates", templateLayoutsArray); - root.SetNamedValue(L"quick-layout-keys", quickLayoutKeysArray); - json::to_file(m_fzData.GetZoneSettingsPath(m_testFolder), root); - - // test - m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); - AppliedLayouts::instance().LoadData(); - Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size()); - - FancyZonesDataTypes::WorkAreaId id{ - .monitorId = { .deviceId = { .id = L"VSC9636", .instanceId = L"5&37ac4db&0&UID160005" }, .serialNumber = L"" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() + FancyZonesDataTypes::WorkAreaId workAreaId1{ + .monitorId = { + .deviceId = { .id = L"id-1", .instanceId = L"id-1", .number = 1 }, + .serialNumber = L"serial-number-1" + }, + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{30387C86-BB15-476D-8683-AF93F6D73E99}").value() + }; + FancyZonesDataTypes::WorkAreaId workAreaId2{ + .monitorId = { + .deviceId = { .id = L"id-2", .instanceId = L"id-2", .number = 2 }, + .serialNumber = L"serial-number-2" }, + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{30387C86-BB15-476D-8683-AF93F6D73E99}").value() + }; + FancyZonesDataTypes::WorkAreaId workAreaId3{ + .monitorId = { + .deviceId = { .id = L"id-1", .instanceId = L"id-1", .number = 1 }, + .serialNumber = L"serial-number-1" }, + .virtualDesktopId = GUID_NULL + }; + FancyZonesDataTypes::WorkAreaId workAreaId4{ + .monitorId = { + .deviceId = { .id = L"id-2", .instanceId = L"id-2", .number = 2 }, + .serialNumber = L"serial-number-2" }, + .virtualDesktopId = GUID_NULL }; - Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value()); - } - TEST_METHOD (MoveAppliedLayoutsFromZonesSettingsNoAppliedLayoutsData) - { - // prepare - json::JsonObject root{}; - json::JsonArray customLayoutsArray{}, templateLayoutsArray{}, quickLayoutKeysArray{}; - root.SetNamedValue(L"custom-zone-sets", customLayoutsArray); - root.SetNamedValue(L"templates", templateLayoutsArray); - root.SetNamedValue(L"quick-layout-keys", quickLayoutKeysArray); - json::to_file(m_fzData.GetZoneSettingsPath(m_testFolder), root); + LayoutData layout1{ .uuid = FancyZonesUtils::GuidFromString(L"{D7DBECFA-23FC-4F45-9B56-51CFA9F6ABA2}").value() }; + LayoutData layout2{ .uuid = FancyZonesUtils::GuidFromString(L"{B9EDB48C-EC48-4E82-993F-A15DC1FF09D3}").value() }; + LayoutData layout3{ .uuid = FancyZonesUtils::GuidFromString(L"{94CF0000-7814-4D72-9624-794060FA269C}").value() }; + LayoutData layout4{ .uuid = FancyZonesUtils::GuidFromString(L"{13FA7ADF-1B6C-4FB6-8142-254B77C128E2}").value() }; + + AppliedLayouts::TAppliedLayoutsMap expected{}; + expected.insert({ workAreaId1, layout1 }); + expected.insert({ workAreaId2, layout2 }); + expected.insert({ workAreaId3, layout3 }); + expected.insert({ workAreaId4, layout4 }); + + AppliedLayouts::instance().SetAppliedLayouts(expected); + AppliedLayouts::instance().SaveData(); - // test - m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); AppliedLayouts::instance().LoadData(); - Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().empty()); - } - - TEST_METHOD (MoveAppliedLayoutsFromZonesSettingsNoFile) - { - // test - m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); - AppliedLayouts::instance().LoadData(); - Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().empty()); + auto actual = AppliedLayouts::instance().GetAppliedLayoutMap(); + Assert::AreEqual(expected.size(), actual.size()); + Assert::IsTrue(expected.at(workAreaId1) == actual.at(workAreaId1)); + Assert::IsTrue(expected.at(workAreaId2) == actual.at(workAreaId2)); + Assert::IsTrue(expected.at(workAreaId3) == actual.at(workAreaId3)); + Assert::IsTrue(expected.at(workAreaId4) == actual.at(workAreaId4)); } TEST_METHOD (CloneDeviceInfo) { FancyZonesDataTypes::WorkAreaId deviceSrc{ .monitorId = { .deviceId = { .id = L"Device1", .instanceId = L"" }, .serialNumber = L"" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{EA6B6934-D55F-49F5-A9A5-CFADE21FFFB8}").value() }; FancyZonesDataTypes::WorkAreaId deviceDst{ .monitorId = { .deviceId = { .id = L"Device2", .instanceId = L"" }, .serialNumber = L"" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{EF1A8099-7D1E-4738-805A-571B31B02674}").value() }; - Assert::IsTrue(AppliedLayouts::instance().ApplyDefaultLayout(deviceSrc)); - Assert::IsTrue(AppliedLayouts::instance().ApplyDefaultLayout(deviceDst)); - + LayoutData layout { .uuid = FancyZonesUtils::GuidFromString(L"{361F96DD-FD10-4D01-ABAC-CC1C857294DD}").value() }; + Assert::IsTrue(AppliedLayouts::instance().ApplyLayout(deviceSrc, layout)); + AppliedLayouts::instance().CloneLayout(deviceSrc, deviceDst); - auto actualMap = AppliedLayouts::instance().GetAppliedLayoutMap(); - Assert::IsFalse(actualMap.find(deviceSrc) == actualMap.end()); - Assert::IsFalse(actualMap.find(deviceDst) == actualMap.end()); - - auto expected = AppliedLayouts::instance().GetDeviceLayout(deviceSrc); - auto actual = AppliedLayouts::instance().GetDeviceLayout(deviceDst); - - Assert::IsTrue(expected.has_value()); - Assert::IsTrue(actual.has_value()); - Assert::IsTrue(expected.value().uuid == actual.value().uuid); - } - - TEST_METHOD (CloneDeviceInfoIntoUnknownDevice) - { - FancyZonesDataTypes::WorkAreaId deviceSrc{ - .monitorId = { .deviceId = { .id = L"Device1", .instanceId = L"" }, .serialNumber = L"" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() - }; - FancyZonesDataTypes::WorkAreaId deviceDst{ - .monitorId = { .deviceId = { .id = L"Device2", .instanceId = L"" }, .serialNumber = L"" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() - }; - - Assert::IsTrue(AppliedLayouts::instance().ApplyDefaultLayout(deviceSrc)); - - AppliedLayouts::instance().CloneLayout(deviceSrc, deviceDst); - - auto actualMap = AppliedLayouts::instance().GetAppliedLayoutMap(); - Assert::IsFalse(actualMap.find(deviceSrc) == actualMap.end()); - Assert::IsFalse(actualMap.find(deviceDst) == actualMap.end()); - - auto expected = AppliedLayouts::instance().GetDeviceLayout(deviceSrc); - auto actual = AppliedLayouts::instance().GetDeviceLayout(deviceDst); - - Assert::IsTrue(expected.has_value()); - Assert::IsTrue(actual.has_value()); - Assert::IsTrue(expected.value().uuid == actual.value().uuid); + Assert::IsTrue(layout == AppliedLayouts::instance().GetDeviceLayout(deviceSrc)); + Assert::IsTrue(layout == AppliedLayouts::instance().GetDeviceLayout(deviceDst)); } TEST_METHOD (CloneDeviceInfoFromUnknownDevice) { FancyZonesDataTypes::WorkAreaId deviceSrc{ .monitorId = { .deviceId = { .id = L"Device1", .instanceId = L"" }, .serialNumber = L"" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{EA6B6934-D55F-49F5-A9A5-CFADE21FFFB8}").value() }; FancyZonesDataTypes::WorkAreaId deviceDst{ .monitorId = { .deviceId = { .id = L"Device2", .instanceId = L"" }, .serialNumber = L"" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{EF1A8099-7D1E-4738-805A-571B31B02674}").value() }; AppliedLayouts::instance().LoadData(); - Assert::IsTrue(AppliedLayouts::instance().ApplyDefaultLayout(deviceDst)); Assert::IsFalse(AppliedLayouts::instance().CloneLayout(deviceSrc, deviceDst)); Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(deviceSrc).has_value()); - Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(deviceDst).has_value()); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(deviceDst).has_value()); } TEST_METHOD (CloneDeviceInfoNullVirtualDesktopId) @@ -389,35 +330,25 @@ namespace FancyZonesUnitTests }; FancyZonesDataTypes::WorkAreaId deviceDst{ .monitorId = { .deviceId = { .id = L"Device2", .instanceId = L"" }, .serialNumber = L"" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{EF1A8099-7D1E-4738-805A-571B31B02674}").value() }; - Assert::IsTrue(AppliedLayouts::instance().ApplyDefaultLayout(deviceSrc)); - Assert::IsTrue(AppliedLayouts::instance().ApplyDefaultLayout(deviceDst)); - + LayoutData layout{ .uuid = FancyZonesUtils::GuidFromString(L"{361F96DD-FD10-4D01-ABAC-CC1C857294DD}").value() }; + Assert::IsTrue(AppliedLayouts::instance().ApplyLayout(deviceSrc, layout)); + AppliedLayouts::instance().CloneLayout(deviceSrc, deviceDst); - auto actualMap = AppliedLayouts::instance().GetAppliedLayoutMap(); - Assert::IsFalse(actualMap.find(deviceSrc) == actualMap.end()); - Assert::IsFalse(actualMap.find(deviceDst) == actualMap.end()); - - auto expected = AppliedLayouts::instance().GetDeviceLayout(deviceSrc); - auto actual = AppliedLayouts::instance().GetDeviceLayout(deviceDst); - - Assert::IsTrue(expected.has_value()); - Assert::IsTrue(actual.has_value()); - Assert::IsTrue(expected.value().uuid == actual.value().uuid); + Assert::IsTrue(layout == AppliedLayouts::instance().GetDeviceLayout(deviceSrc)); + Assert::IsTrue(layout == AppliedLayouts::instance().GetDeviceLayout(deviceDst)); } TEST_METHOD (ApplyLayout) { - // prepare - FancyZonesDataTypes::WorkAreaId deviceId { + FancyZonesDataTypes::WorkAreaId workAreaId { .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" }, .serialNumber = L"" }, .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value() }; - // test LayoutData expectedLayout { .uuid = FancyZonesUtils::GuidFromString(L"{33A2B101-06E0-437B-A61E-CDBECF502906}").value(), .type = FancyZonesDataTypes::ZoneSetLayoutType::Focus, @@ -427,47 +358,30 @@ namespace FancyZonesUnitTests .sensitivityRadius = 30 }; - AppliedLayouts::instance().ApplyLayout(deviceId, expectedLayout); + AppliedLayouts::instance().ApplyLayout(workAreaId, expectedLayout); - Assert::IsFalse(AppliedLayouts::instance().GetAppliedLayoutMap().empty()); - Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(deviceId).has_value()); - - auto actual = AppliedLayouts::instance().GetAppliedLayoutMap().find(deviceId)->second; - Assert::IsTrue(expectedLayout.type == actual.type); - Assert::AreEqual(expectedLayout.showSpacing, actual.showSpacing); - Assert::AreEqual(expectedLayout.spacing, actual.spacing); - Assert::AreEqual(expectedLayout.zoneCount, actual.zoneCount); - Assert::AreEqual(expectedLayout.sensitivityRadius, actual.sensitivityRadius); + Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(workAreaId).has_value()); + Assert::IsTrue(expectedLayout == AppliedLayouts::instance().GetAppliedLayoutMap().find(workAreaId)->second); } TEST_METHOD (ApplyLayoutReplace) { // prepare - FancyZonesDataTypes::WorkAreaId deviceId{ + FancyZonesDataTypes::WorkAreaId workAreaId{ .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" }, .serialNumber = L"" }, .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value() }; + + LayoutData layout{ + .uuid = FancyZonesUtils::GuidFromString(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}").value(), + .type = FancyZonesDataTypes::ZoneSetLayoutType::Rows, + .showSpacing = true, + .spacing = 3, + .zoneCount = 4, + .sensitivityRadius = 22 + }; - json::JsonObject root{}; - json::JsonArray layoutsArray{}; - { - json::JsonObject layout{}; - layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::UuidID, json::value(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}")); - layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::TypeID, json::value(FancyZonesDataTypes::TypeToString(FancyZonesDataTypes::ZoneSetLayoutType::Rows))); - layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ShowSpacingID, json::value(true)); - layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SpacingID, json::value(3)); - layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ZoneCountID, json::value(4)); - layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(22)); - - json::JsonObject obj{}; - obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::DeviceIdID, json::value(L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{61FA9FC0-26A6-4B37-A834-491C148DFC57}")); - obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID, layout); - - layoutsArray.Append(obj); - } - root.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID, layoutsArray); - json::to_file(AppliedLayouts::AppliedLayoutsFileName(), root); - AppliedLayouts::instance().LoadData(); + AppliedLayouts::instance().SetAppliedLayouts({ {workAreaId, layout} }); // test LayoutData expectedLayout{ @@ -479,18 +393,8 @@ namespace FancyZonesUnitTests .sensitivityRadius = 30 }; - AppliedLayouts::instance().ApplyLayout(deviceId, expectedLayout); - - Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size()); - Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(deviceId).has_value()); - - auto actual = AppliedLayouts::instance().GetAppliedLayoutMap().find(deviceId)->second; - Assert::AreEqual(FancyZonesUtils::GuidToString(expectedLayout.uuid).value().c_str(), FancyZonesUtils::GuidToString(actual.uuid).value().c_str()); - Assert::IsTrue(expectedLayout.type == actual.type); - Assert::AreEqual(expectedLayout.showSpacing, actual.showSpacing); - Assert::AreEqual(expectedLayout.spacing, actual.spacing); - Assert::AreEqual(expectedLayout.zoneCount, actual.zoneCount); - Assert::AreEqual(expectedLayout.sensitivityRadius, actual.sensitivityRadius); + AppliedLayouts::instance().ApplyLayout(workAreaId, expectedLayout); + Assert::IsTrue(expectedLayout == AppliedLayouts::instance().GetDeviceLayout(workAreaId)); } TEST_METHOD (ApplyDefaultLayout) @@ -553,4 +457,245 @@ namespace FancyZonesUnitTests Assert::IsFalse(AppliedLayouts::instance().IsLayoutApplied(id2)); } }; + + TEST_CLASS (AppliedLayoutsSyncVirtualDesktops) + { + const GUID virtualDesktop1 = FancyZonesUtils::GuidFromString(L"{30387C86-BB15-476D-8683-AF93F6D73E99}").value(); + const GUID virtualDesktop2 = FancyZonesUtils::GuidFromString(L"{65F6343A-868F-47EE-838E-55A178A7FB7A}").value(); + const GUID deletedVirtualDesktop = FancyZonesUtils::GuidFromString(L"{2D9F3E2D-F61D-4618-B35D-85C9B8DFDFD8}").value(); + + LayoutData layout1{ .uuid = FancyZonesUtils::GuidFromString(L"{D7DBECFA-23FC-4F45-9B56-51CFA9F6ABA2}").value() }; + LayoutData layout2{ .uuid = FancyZonesUtils::GuidFromString(L"{B9EDB48C-EC48-4E82-993F-A15DC1FF09D3}").value() }; + LayoutData layout3{ .uuid = FancyZonesUtils::GuidFromString(L"{94CF0000-7814-4D72-9624-794060FA269C}").value() }; + LayoutData layout4{ .uuid = FancyZonesUtils::GuidFromString(L"{13FA7ADF-1B6C-4FB6-8142-254B77C128E2}").value() }; + + FancyZonesDataTypes::WorkAreaId GetWorkAreaID(int number, GUID virtualDesktop) + { + return FancyZonesDataTypes::WorkAreaId{ + .monitorId = { + .deviceId = { + .id = std::wstring(L"id-") + std::to_wstring(number), + .instanceId = std::wstring(L"id-") + std::to_wstring(number), + .number = number + }, + .serialNumber = std::wstring(L"serial-number-") + std::to_wstring(number) + }, + .virtualDesktopId = virtualDesktop + }; + } + + TEST_METHOD_INITIALIZE(Init) + { + AppliedLayouts::instance().LoadData(); + } + + TEST_METHOD_CLEANUP(CleanUp) + { + std::filesystem::remove(AppliedLayouts::AppliedLayoutsFileName()); + } + + TEST_METHOD(SyncVirtualDesktops_SwitchVirtualDesktop) + { + AppliedLayouts::TAppliedLayoutsMap layouts{}; + layouts.insert({ GetWorkAreaID(1, virtualDesktop1), layout1 }); + layouts.insert({ GetWorkAreaID(2, virtualDesktop1), layout2 }); + layouts.insert({ GetWorkAreaID(1, virtualDesktop2), layout3 }); + layouts.insert({ GetWorkAreaID(2, virtualDesktop2), layout4 }); + AppliedLayouts::instance().SetAppliedLayouts(layouts); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = virtualDesktop2; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1, virtualDesktop2 } }; + AppliedLayouts::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(layout1 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, virtualDesktop1))); + Assert::IsTrue(layout2 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, virtualDesktop1))); + Assert::IsTrue(layout3 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, virtualDesktop2))); + Assert::IsTrue(layout4 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, virtualDesktop2))); + } + + TEST_METHOD (SyncVirtualDesktops_CurrentVirtualDesktopDeleted) + { + AppliedLayouts::TAppliedLayoutsMap layouts{}; + layouts.insert({ GetWorkAreaID(1, virtualDesktop1), layout1 }); + layouts.insert({ GetWorkAreaID(2, virtualDesktop1), layout2 }); + layouts.insert({ GetWorkAreaID(1, deletedVirtualDesktop), layout3 }); + layouts.insert({ GetWorkAreaID(2, deletedVirtualDesktop), layout4 }); + AppliedLayouts::instance().SetAppliedLayouts(layouts); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = deletedVirtualDesktop; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1 } }; + AppliedLayouts::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(layout1 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, virtualDesktop1))); + Assert::IsTrue(layout2 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, virtualDesktop1))); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, deletedVirtualDesktop)).has_value()); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, deletedVirtualDesktop)).has_value()); + } + + TEST_METHOD (SyncVirtualDesktops_NotCurrentVirtualDesktopDeleted) + { + AppliedLayouts::TAppliedLayoutsMap layouts{}; + layouts.insert({ GetWorkAreaID(1, virtualDesktop1), layout1 }); + layouts.insert({ GetWorkAreaID(2, virtualDesktop1), layout2 }); + layouts.insert({ GetWorkAreaID(1, deletedVirtualDesktop), layout3 }); + layouts.insert({ GetWorkAreaID(2, deletedVirtualDesktop), layout4 }); + AppliedLayouts::instance().SetAppliedLayouts(layouts); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = virtualDesktop1; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1 } }; + AppliedLayouts::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(layout1 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, virtualDesktop1))); + Assert::IsTrue(layout2 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, virtualDesktop1))); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, deletedVirtualDesktop)).has_value()); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, deletedVirtualDesktop)).has_value()); + } + + TEST_METHOD (SyncVirtualDesktops_AllIdsFromRegistryAreNew) + { + AppliedLayouts::TAppliedLayoutsMap layouts{}; + layouts.insert({ GetWorkAreaID(1, deletedVirtualDesktop), layout1 }); + layouts.insert({ GetWorkAreaID(2, deletedVirtualDesktop), layout2 }); + AppliedLayouts::instance().SetAppliedLayouts(layouts); + + GUID currentVirtualDesktop = virtualDesktop1; + GUID lastUsedVirtualDesktop = deletedVirtualDesktop; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1, virtualDesktop2 } }; + AppliedLayouts::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(layout1 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, virtualDesktop1))); + Assert::IsTrue(layout2 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, virtualDesktop1))); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, virtualDesktop2)).has_value()); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, virtualDesktop2)).has_value()); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, deletedVirtualDesktop)).has_value()); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, deletedVirtualDesktop)).has_value()); + } + + TEST_METHOD (SyncVirtualDesktop_NoDesktopsInRegistry) + { + AppliedLayouts::TAppliedLayoutsMap layouts{}; + layouts.insert({ GetWorkAreaID(1, deletedVirtualDesktop), layout1 }); + layouts.insert({ GetWorkAreaID(2, deletedVirtualDesktop), layout2 }); + AppliedLayouts::instance().SetAppliedLayouts(layouts); + + GUID currentVirtualDesktop = GUID_NULL; + GUID lastUsedVirtualDesktop = deletedVirtualDesktop; + std::optional> virtualDesktopsInRegistry = std::nullopt; + AppliedLayouts::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(layout1 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, GUID_NULL))); + Assert::IsTrue(layout2 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, GUID_NULL))); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, deletedVirtualDesktop)).has_value()); + Assert::IsFalse(AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, deletedVirtualDesktop)).has_value()); + } + + TEST_METHOD(SyncVirtualDesktops_SwithVirtualDesktopFirstTime) + { + AppliedLayouts::TAppliedLayoutsMap layouts{}; + layouts.insert({ GetWorkAreaID(1, GUID_NULL), layout1 }); + layouts.insert({ GetWorkAreaID(2, GUID_NULL), layout2 }); + AppliedLayouts::instance().SetAppliedLayouts(layouts); + + GUID currentVirtualDesktop = virtualDesktop2; + GUID lastUsedVirtualDesktop = GUID_NULL; + std::optional> virtualDesktopsInRegistry = { { virtualDesktop1, virtualDesktop2 } }; + AppliedLayouts::instance().SyncVirtualDesktops(currentVirtualDesktop, lastUsedVirtualDesktop, virtualDesktopsInRegistry); + + Assert::IsTrue(layout1 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, virtualDesktop1))); + Assert::IsTrue(layout2 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, virtualDesktop1))); + Assert::IsTrue(layout1 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(1, virtualDesktop2))); + Assert::IsTrue(layout2 == AppliedLayouts::instance().GetDeviceLayout(GetWorkAreaID(2, virtualDesktop2))); + } + }; + + TEST_CLASS (AppliedLayoutsFromOutdatedFileMappingUnitTests) + { + FancyZonesData& m_fzData = FancyZonesDataInstance(); + std::wstring m_testFolder = L"FancyZonesUnitTests"; + std::wstring m_testFolderPath = PTSettingsHelper::get_module_save_folder_location(m_testFolder); + + TEST_METHOD_INITIALIZE(Init) + { + m_fzData.SetSettingsModulePath(m_testFolder); + } + + TEST_METHOD_CLEANUP(CleanUp) + { + // MoveAppliedLayoutsFromZonesSettings creates all of these files, clean up + std::filesystem::remove(AppliedLayouts::AppliedLayoutsFileName()); + std::filesystem::remove(CustomLayouts::CustomLayoutsFileName()); + std::filesystem::remove(LayoutHotkeys::LayoutHotkeysFileName()); + std::filesystem::remove(LayoutTemplates::LayoutTemplatesFileName()); + std::filesystem::remove_all(m_testFolderPath); + AppliedLayouts::instance().LoadData(); // clean data + } + + TEST_METHOD (MoveAppliedLayoutsFromZonesSettings) + { + // prepare + json::JsonObject root{}; + json::JsonArray devicesArray{}, customLayoutsArray{}, templateLayoutsArray{}, quickLayoutKeysArray{}; + + { + json::JsonObject activeZoneset{}; + activeZoneset.SetNamedValue(L"uuid", json::value(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}")); + activeZoneset.SetNamedValue(L"type", json::value(FancyZonesDataTypes::TypeToString(FancyZonesDataTypes::ZoneSetLayoutType::Rows))); + + json::JsonObject obj{}; + obj.SetNamedValue(L"device-id", json::value(L"VSC9636#5&37ac4db&0&UID160005_3840_2160_{00000000-0000-0000-0000-000000000000}")); + obj.SetNamedValue(L"active-zoneset", activeZoneset); + + obj.SetNamedValue(L"editor-show-spacing", json::value(true)); + obj.SetNamedValue(L"editor-spacing", json::value(3)); + obj.SetNamedValue(L"editor-zone-count", json::value(4)); + obj.SetNamedValue(L"editor-sensitivity-radius", json::value(22)); + + devicesArray.Append(obj); + } + + root.SetNamedValue(L"devices", devicesArray); + root.SetNamedValue(L"custom-zone-sets", customLayoutsArray); + root.SetNamedValue(L"templates", templateLayoutsArray); + root.SetNamedValue(L"quick-layout-keys", quickLayoutKeysArray); + json::to_file(m_fzData.GetZoneSettingsPath(m_testFolder), root); + + // test + m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); + AppliedLayouts::instance().LoadData(); + Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size()); + + FancyZonesDataTypes::WorkAreaId id{ + .monitorId = { .deviceId = { .id = L"VSC9636", .instanceId = L"5&37ac4db&0&UID160005" }, .serialNumber = L"" }, + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() + }; + Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value()); + } + + TEST_METHOD (MoveAppliedLayoutsFromZonesSettingsNoAppliedLayoutsData) + { + // prepare + json::JsonObject root{}; + json::JsonArray customLayoutsArray{}, templateLayoutsArray{}, quickLayoutKeysArray{}; + root.SetNamedValue(L"custom-zone-sets", customLayoutsArray); + root.SetNamedValue(L"templates", templateLayoutsArray); + root.SetNamedValue(L"quick-layout-keys", quickLayoutKeysArray); + json::to_file(m_fzData.GetZoneSettingsPath(m_testFolder), root); + + // test + m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); + AppliedLayouts::instance().LoadData(); + Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().empty()); + } + + TEST_METHOD (MoveAppliedLayoutsFromZonesSettingsNoFile) + { + // test + m_fzData.ReplaceZoneSettingsFileFromOlderVersions(); + AppliedLayouts::instance().LoadData(); + Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().empty()); + } + }; } \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkAreaIdTests.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkAreaIdTests.Spec.cpp index db5c660db0..5b024b718d 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkAreaIdTests.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkAreaIdTests.Spec.cpp @@ -43,11 +43,11 @@ namespace FancyZonesUnitTests Assert::IsFalse(id1 == id2); } - TEST_METHOD (VirtualDesktopNull) + TEST_METHOD (VirtualDesktopDifferent) { FancyZonesDataTypes::WorkAreaId id1{ .monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" }, - .virtualDesktopId = GUID_NULL + .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{F21F6F29-76FD-4FC1-8970-17AB8AD64847}").value() }; FancyZonesDataTypes::WorkAreaId id2{ @@ -55,14 +55,14 @@ namespace FancyZonesUnitTests .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value() }; - Assert::IsTrue(id1 == id2); + Assert::IsFalse(id1 == id2); } - TEST_METHOD (VirtualDesktopDifferent) + TEST_METHOD (VirtualDesktopNull) { FancyZonesDataTypes::WorkAreaId id1{ .monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" }, - .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{F21F6F29-76FD-4FC1-8970-17AB8AD64847}").value() + .virtualDesktopId = GUID_NULL }; FancyZonesDataTypes::WorkAreaId id2{