diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index 9d42d9709791..020b1ec3b059 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -129,17 +129,16 @@ struct FancyZones : public winrt::implements workArea) noexcept; + bool ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, WorkArea* const workArea) noexcept; void RegisterVirtualDesktopUpdates() noexcept; void UpdateHotkey(int hotkeyId, const PowerToysSettings::HotkeyObject& hotkeyObject, bool enable) noexcept; - std::pair, ZoneIndexSet> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map>& workAreaMap) noexcept; - void MoveWindowIntoZone(HWND window, std::shared_ptr workArea, const ZoneIndexSet& zoneIndexSet) noexcept; + std::pair GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map>& workAreas) noexcept; + void MoveWindowIntoZone(HWND window, WorkArea* const workArea, const ZoneIndexSet& zoneIndexSet) noexcept; bool MoveToAppLastZone(HWND window, HMONITOR active, HMONITOR primary) noexcept; - void RefreshWorkAreaWindows(bool updatePositions); - + void OnEditorExitEvent() noexcept; void UpdateZoneSets() noexcept; bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept; @@ -156,7 +155,7 @@ struct FancyZones : public winrt::implements m_windowDrag{}; - MonitorWorkAreaHandler m_workAreaHandler; + MonitorWorkAreaMap m_workAreaHandler; DraggingState m_draggingState; wil::unique_handle m_terminateEditorEvent; // Handle of FancyZonesEditor.exe we launch and wait on @@ -283,7 +282,7 @@ FancyZones::VirtualDesktopChanged() noexcept void FancyZones::MoveSizeStart(HWND window, HMONITOR monitor) { - m_windowDrag = WindowDrag::Create(window, m_workAreaHandler.GetWorkAreasByDesktopId(VirtualDesktop::instance().GetCurrentVirtualDesktopId())); + m_windowDrag = WindowDrag::Create(window, m_workAreaHandler.GetAllWorkAreas()); if (m_windowDrag) { if (FancyZonesSettings::settings().spanZonesAcrossMonitors) @@ -321,70 +320,54 @@ void FancyZones::MoveSizeEnd() } } -std::pair, ZoneIndexSet> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map>& workAreaMap) noexcept +std::pair FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map>& workAreas) noexcept { - if (monitor) + for (const auto& [workAreaMonitor, workArea] : workAreas) { - if (workAreaMap.contains(monitor)) - { - auto workArea = workAreaMap.at(monitor); - return std::pair, ZoneIndexSet>{ workArea, workArea->GetWindowZoneIndexes(window) }; - } - else + if (workAreaMonitor == monitor && workArea) { - Logger::debug(L"No work area for the currently active monitor."); - } - } - else - { - for (const auto& [mon, workArea] : workAreaMap) - { - auto zoneIndexSet = workArea->GetWindowZoneIndexes(window); - if (!zoneIndexSet.empty()) - { - return std::pair, ZoneIndexSet>{ workArea, zoneIndexSet }; - } + return std::pair{ workArea.get(), workArea->GetWindowZoneIndexes(window) }; } } - return std::pair, ZoneIndexSet>{ nullptr, {} }; + Logger::error(L"No work area for the currently active monitor."); + return std::pair{ nullptr, {} }; } -void FancyZones::MoveWindowIntoZone(HWND window, std::shared_ptr workArea, const ZoneIndexSet& zoneIndexSet) noexcept +void FancyZones::MoveWindowIntoZone(HWND window, WorkArea* const workArea, const ZoneIndexSet& zoneIndexSet) noexcept { if (workArea) { Trace::FancyZones::SnapNewWindowIntoZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get()); workArea->MoveWindowIntoZoneByIndexSet(window, zoneIndexSet); + AppZoneHistory::instance().UpdateProcessIdToHandleMap(window, workArea->UniqueId()); } - - AppZoneHistory::instance().UpdateProcessIdToHandleMap(window, workArea->UniqueId()); } bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR active, HMONITOR primary) noexcept { - auto workAreaMap = m_workAreaHandler.GetWorkAreasByDesktopId(VirtualDesktop::instance().GetCurrentVirtualDesktopId()); - if (workAreaMap.empty()) + const auto& workAreas = m_workAreaHandler.GetAllWorkAreas(); + if (workAreas.empty()) { Logger::trace(L"No work area for the current desktop."); return false; } // Search application history on currently active monitor. - std::pair, ZoneIndexSet> appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, workAreaMap); + auto appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, workAreas); // No application history on currently active monitor if (appZoneHistoryInfo.second.empty()) { // Search application history on primary monitor. - appZoneHistoryInfo = GetAppZoneHistoryInfo(window, primary, workAreaMap); + appZoneHistoryInfo = GetAppZoneHistoryInfo(window, primary, workAreas); } // No application history on currently active and primary monitors if (appZoneHistoryInfo.second.empty()) { // Search application history on remaining monitors. - appZoneHistoryInfo = GetAppZoneHistoryInfo(window, nullptr, workAreaMap); + appZoneHistoryInfo = GetAppZoneHistoryInfo(window, nullptr, workAreas); } if (!appZoneHistoryInfo.second.empty()) @@ -400,25 +383,6 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR active, HMONITOR primar return false; } -void FancyZones::RefreshWorkAreaWindows(bool updatePositions) -{ - auto activeWorkAreas = m_workAreaHandler.GetWorkAreasByDesktopId(VirtualDesktop::instance().GetCurrentVirtualDesktopId()); - for (const auto& window : VirtualDesktop::instance().GetWindowsFromCurrentDesktop()) - { - auto zoneIndexSet = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window); - if (zoneIndexSet.size() == 0) - { - continue; - } - - auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); - if (monitor && activeWorkAreas.contains(monitor)) - { - activeWorkAreas.at(monitor)->MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, updatePositions); - } - } -} - void FancyZones::WindowCreated(HWND window) noexcept { const bool moveToAppLastZone = FancyZonesSettings::settings().appLastZone_moveWindows; @@ -457,9 +421,19 @@ void FancyZones::WindowCreated(HWND window) noexcept } bool movedToAppLastZone = false; - if (moveToAppLastZone) + if (FancyZonesSettings::settings().spanZonesAcrossMonitors) + { + if (moveToAppLastZone) + { + movedToAppLastZone = MoveToAppLastZone(window, nullptr, nullptr); + } + } + else { - movedToAppLastZone = MoveToAppLastZone(window, active, primary); + if (moveToAppLastZone) + { + movedToAppLastZone = MoveToAppLastZone(window, active, primary); + } } // Open on active monitor if window wasn't zoned @@ -609,7 +583,6 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa { // Changes in taskbar position resulted in different size of work area. // Invalidate cached work-areas so they can be recreated with latest information. - m_workAreaHandler.Clear(); OnDisplayChange(DisplayChangeType::WorkArea); } } @@ -618,7 +591,6 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa case WM_DISPLAYCHANGE: { // Display resolution changed. Invalidate cached work-areas so they can be recreated with latest information. - m_workAreaHandler.Clear(); OnDisplayChange(DisplayChangeType::DisplayChange); } break; @@ -740,42 +712,38 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept } UpdateWorkAreas(); - RefreshWorkAreaWindows(FancyZonesSettings::settings().displayChange_moveWindows && changeType != DisplayChangeType::VirtualDesktop); } void FancyZones::AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& id) noexcept { - if (m_workAreaHandler.IsNewWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), monitor)) + wil::unique_cotaskmem_string virtualDesktopIdStr; + if (!SUCCEEDED(StringFromCLSID(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), &virtualDesktopIdStr))) { - wil::unique_cotaskmem_string virtualDesktopIdStr; - if (!SUCCEEDED(StringFromCLSID(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), &virtualDesktopIdStr))) - { - Logger::debug(L"Add new work area on virtual desktop {}", virtualDesktopIdStr.get()); - } + Logger::debug(L"Add new work area on virtual desktop {}", virtualDesktopIdStr.get()); + } - FancyZonesDataTypes::WorkAreaId parentId{}; - auto parentArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetPreviousVirtualDesktopId(), monitor); - if (parentArea) - { - parentId = parentArea->UniqueId(); - } + FancyZonesDataTypes::WorkAreaId parentId{}; + auto parentArea = m_workAreaHandler.GetWorkArea(monitor); + if (parentArea) + { + parentId = parentArea->UniqueId(); + } - FancyZonesUtils::Rect rect{}; - if (monitor) - { - rect = MonitorUtils::GetWorkAreaRect(monitor); - } - else - { - rect = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>(); - } + FancyZonesUtils::Rect rect{}; + if (monitor) + { + rect = MonitorUtils::GetWorkAreaRect(monitor); + } + else + { + rect = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>(); + } - auto workArea = MakeWorkArea(m_hinstance, id, parentId, rect); - if (workArea) - { - m_workAreaHandler.AddWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), monitor, workArea); - AppliedLayouts::instance().SaveData(); - } + auto workArea = WorkArea::Create(m_hinstance, id, parentId, rect); + if (workArea) + { + m_workAreaHandler.AddWorkArea(monitor, std::move(workArea)); + AppliedLayouts::instance().SaveData(); } } @@ -795,6 +763,8 @@ LRESULT CALLBACK FancyZones::s_WndProc(HWND window, UINT message, WPARAM wparam, void FancyZones::UpdateWorkAreas() noexcept { + m_workAreaHandler.Clear(); + if (FancyZonesSettings::settings().spanZonesAcrossMonitors) { FancyZonesDataTypes::WorkAreaId workAreaId; @@ -822,7 +792,7 @@ void FancyZones::CycleWindows(bool reverse) noexcept auto window = GetForegroundWindow(); HMONITOR current = WorkAreaKeyFromWindow(window); - auto workArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), current); + auto workArea = m_workAreaHandler.GetWorkArea(current); if (workArea) { workArea->CycleWindows(window, reverse); @@ -840,13 +810,13 @@ bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexce auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current); do { - auto workArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), *currMonitorInfo); + auto workArea = m_workAreaHandler.GetWorkArea(*currMonitorInfo); if (workArea && workArea->MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, false /* cycle through zones */)) { // unassign from previous work area - for (auto& prevWorkArea : m_workAreaHandler.GetAllWorkAreas()) + for (auto& [_, prevWorkArea] : m_workAreaHandler.GetAllWorkAreas()) { - if (workArea != prevWorkArea) + if (prevWorkArea && workArea != prevWorkArea.get()) { prevWorkArea->UnsnapWindow(window); } @@ -876,7 +846,7 @@ bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexce } else { - auto workArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), current); + auto workArea = m_workAreaHandler.GetWorkArea(current); // Single monitor environment, or combined multi-monitor environment. if (FancyZonesSettings::settings().restoreSize) { @@ -918,7 +888,7 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept { // Multi monitor environment. // First, try to stay on the same monitor - bool success = ProcessDirectedSnapHotkey(window, vkCode, false, m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), current)); + bool success = ProcessDirectedSnapHotkey(window, vkCode, false, m_workAreaHandler.GetWorkArea(current)); if (success) { return true; @@ -937,7 +907,7 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept } else { - auto workArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), monitor); + auto workArea = m_workAreaHandler.GetWorkArea(monitor); if (workArea) { const auto& layout = workArea->GetLayout(); @@ -977,9 +947,9 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept if (workArea) { workArea->MoveWindowIntoZoneByIndexSet(window, { trueZoneIdx }); + Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get()); } - Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get()); return true; } @@ -989,7 +959,7 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept // Sanity check: the current monitor is valid if (currentMonitorRect.top <= currentMonitorRect.bottom) { - auto workArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), current); + auto workArea = m_workAreaHandler.GetWorkArea(current); if (workArea) { const auto& layout = workArea->GetLayout(); @@ -1027,9 +997,9 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept if (workArea) { workArea->MoveWindowIntoZoneByIndexSet(window, { trueZoneIdx }); + Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get()); } - - Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get()); + return true; } else @@ -1041,7 +1011,7 @@ bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept else { // Single monitor environment, or combined multi-monitor environment. - return ProcessDirectedSnapHotkey(window, vkCode, true, m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), current)); + return ProcessDirectedSnapHotkey(window, vkCode, true, m_workAreaHandler.GetWorkArea(current)); } } @@ -1057,7 +1027,7 @@ bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept return (vkCode == VK_LEFT || vkCode == VK_RIGHT) && OnSnapHotkeyBasedOnZoneNumber(window, vkCode); } -bool FancyZones::ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, std::shared_ptr workArea) noexcept +bool FancyZones::ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, WorkArea* const workArea) noexcept { // Check whether Alt is used in the shortcut key combination if (GetAsyncKeyState(VK_MENU) & 0x8000) @@ -1085,7 +1055,6 @@ void FancyZones::RegisterVirtualDesktopUpdates() noexcept auto guids = VirtualDesktop::instance().GetVirtualDesktopIdsFromRegistry(); if (guids.has_value()) { - m_workAreaHandler.RegisterUpdates(*guids); AppZoneHistory::instance().RemoveDeletedVirtualDesktops(*guids); AppliedLayouts::instance().RemoveDeletedVirtualDesktops(*guids); } @@ -1156,12 +1125,13 @@ void FancyZones::OnEditorExitEvent() noexcept void FancyZones::UpdateZoneSets() noexcept { - for (auto workArea : m_workAreaHandler.GetAllWorkAreas()) + for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas()) { - workArea->UpdateActiveZoneSet(); + if (workArea) + { + workArea->UpdateActiveZoneSet(); + } } - - RefreshWorkAreaWindows(FancyZonesSettings::settings().zoneSetChange_moveWindows); } bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept @@ -1177,7 +1147,7 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept { HMONITOR monitor = WorkAreaKeyFromWindow(window); - auto workArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), monitor); + auto workArea = m_workAreaHandler.GetWorkArea(monitor); if (!workArea) { Logger::error(L"No work area for processing snap hotkey"); @@ -1222,20 +1192,26 @@ void FancyZones::ApplyQuickLayout(int key) noexcept return; } - auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(VirtualDesktop::instance().GetCurrentVirtualDesktopId()); - AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), layout.value()); - AppliedLayouts::instance().SaveData(); - UpdateZoneSets(); - FlashZones(); + auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(); + if (workArea) + { + AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), layout.value()); + AppliedLayouts::instance().SaveData(); + UpdateZoneSets(); + FlashZones(); + } } void FancyZones::FlashZones() noexcept { if (FancyZonesSettings::settings().flashZonesOnQuickSwitch && !m_draggingState.IsDragging()) { - for (auto [monitor, workArea] : m_workAreaHandler.GetWorkAreasByDesktopId(VirtualDesktop::instance().GetCurrentVirtualDesktopId())) + for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas()) { - workArea->FlashZones(); + if (workArea) + { + workArea->FlashZones(); + } } } } @@ -1252,10 +1228,10 @@ std::vector FancyZones::GetMonitorsSorted() noexcept std::vector> FancyZones::GetRawMonitorData() noexcept { std::vector> monitorInfo; - const auto& activeWorkAreaMap = m_workAreaHandler.GetWorkAreasByDesktopId(VirtualDesktop::instance().GetCurrentVirtualDesktopId()); + const auto& activeWorkAreaMap = m_workAreaHandler.GetAllWorkAreas(); for (const auto& [monitor, workArea] : activeWorkAreaMap) { - if (workArea->GetLayout() != nullptr) + if (workArea && workArea->GetLayout() != nullptr) { MONITORINFOEX mi; mi.cbSize = sizeof(mi); diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj index 7209e35a1952..2fc91a6f5eaa 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj @@ -59,7 +59,7 @@ - + @@ -113,7 +113,7 @@ - + Create diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters index e3e21c934a07..76bf858a576d 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 @@ -197,7 +197,7 @@ Source Files - + Source Files diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.cpp b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.cpp deleted file mode 100644 index ec9722179408..000000000000 --- a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "pch.h" -#include "MonitorWorkAreaHandler.h" -#include "VirtualDesktop.h" -#include "WorkArea.h" -#include "util.h" - -#include - -std::shared_ptr MonitorWorkAreaHandler::GetWorkArea(const GUID& desktopId, HMONITOR monitor) -{ - auto desktopIt = workAreaMap.find(desktopId); - if (desktopIt != workAreaMap.end()) - { - auto& perDesktopData = desktopIt->second; - auto monitorIt = perDesktopData.find(monitor); - if (monitorIt != std::end(perDesktopData)) - { - return monitorIt->second; - } - } - return nullptr; -} - -std::shared_ptr MonitorWorkAreaHandler::GetWorkAreaFromCursor(const GUID& desktopId) -{ - auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL); - if (allMonitorsWorkArea) - { - // First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle) - return allMonitorsWorkArea; - } - else - { - // Otherwise, look for the work area based on cursor position - POINT cursorPoint; - if (!GetCursorPos(&cursorPoint)) - { - return nullptr; - } - - return GetWorkArea(desktopId, MonitorFromPoint(cursorPoint, MONITOR_DEFAULTTONULL)); - } -} - -std::shared_ptr MonitorWorkAreaHandler::GetWorkArea(HWND window, const GUID& desktopId) -{ - auto allMonitorsWorkArea = GetWorkArea(desktopId, NULL); - if (allMonitorsWorkArea) - { - // First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle) - return allMonitorsWorkArea; - } - else - { - // Otherwise, look for the work area based on the window's position - HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); - return GetWorkArea(desktopId, monitor); - } -} - -const std::unordered_map>& MonitorWorkAreaHandler::GetWorkAreasByDesktopId(const GUID& desktopId) -{ - if (workAreaMap.contains(desktopId)) - { - return workAreaMap[desktopId]; - } - - static const std::unordered_map> empty{}; - return empty; -} - -std::vector> MonitorWorkAreaHandler::GetAllWorkAreas() -{ - std::vector> workAreas{}; - for (const auto& [desktopId, perDesktopData] : workAreaMap) - { - std::transform(std::begin(perDesktopData), - std::end(perDesktopData), - std::back_inserter(workAreas), - [](const auto& item) { return item.second; }); - } - return workAreas; -} - -void MonitorWorkAreaHandler::AddWorkArea(const GUID& desktopId, HMONITOR monitor, std::shared_ptr& workArea) -{ - if (!workAreaMap.contains(desktopId)) - { - workAreaMap[desktopId] = {}; - - auto desktopIdStr = FancyZonesUtils::GuidToString(desktopId); - if (desktopIdStr) - { - Logger::info(L"Add work area on the desktop {}", desktopIdStr.value()); - } - } - auto& perDesktopData = workAreaMap[desktopId]; - perDesktopData[monitor] = std::move(workArea); -} - -bool MonitorWorkAreaHandler::IsNewWorkArea(const GUID& desktopId, HMONITOR monitor) -{ - if (workAreaMap.contains(desktopId)) - { - const auto& perDesktopData = workAreaMap[desktopId]; - if (perDesktopData.contains(monitor)) - { - return false; - } - } - return true; -} - -void MonitorWorkAreaHandler::RegisterUpdates(const std::vector& active) -{ - std::unordered_set activeVirtualDesktops(std::begin(active), std::end(active)); - for (auto desktopIt = std::begin(workAreaMap); desktopIt != std::end(workAreaMap);) - { - auto activeIt = activeVirtualDesktops.find(desktopIt->first); - if (activeIt == std::end(activeVirtualDesktops)) - { - // virtual desktop deleted, remove entry from the map - desktopIt = workAreaMap.erase(desktopIt); - } - else - { - activeVirtualDesktops.erase(desktopIt->first); // virtual desktop already in map, skip it - ++desktopIt; - } - } - // register new virtual desktops, if any - for (const auto& id : activeVirtualDesktops) - { - workAreaMap[id] = {}; - } -} - -void MonitorWorkAreaHandler::Clear() -{ - workAreaMap.clear(); -} diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.h b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.h deleted file mode 100644 index 191b82d7b30e..000000000000 --- a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaHandler.h +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include "GuidUtils.h" - -class WorkArea; -struct ZoneColors; -enum struct OverlappingZonesAlgorithm; - -class MonitorWorkAreaHandler -{ -public: - /** - * Get work area based on virtual desktop id and monitor handle. - * - * @param[in] desktopId Virtual desktop identifier. - * @param[in] monitor Monitor handle. - * - * @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). - */ - std::shared_ptr GetWorkArea(const GUID& desktopId, HMONITOR monitor); - - /** - * Get work area based on virtual desktop id and the current cursor position. - * - * @param[in] desktopId Virtual desktop identifier. - * - * @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). - */ - std::shared_ptr GetWorkAreaFromCursor(const GUID& desktopId); - - /** - * Get work area on which specified window is located. - * - * @param[in] window Window handle. - * @param[in] desktopId GUID current desktop id - * - * @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). - */ - std::shared_ptr GetWorkArea(HWND window, const GUID& desktopId); - - /** - * Get map of all work areas on single virtual desktop. Key in the map is monitor handle, while value - * represents single work area. - * - * @param[in] desktopId Virtual desktop identifier. - * - * @returns Map containing pairs of monitor and work area for that monitor (within same virtual desktop). - */ - const std::unordered_map>& GetWorkAreasByDesktopId(const GUID& desktopId); - - /** - * @returns All registered work areas. - */ - std::vector> GetAllWorkAreas(); - - /** - * Register new work area. - * - * @param[in] desktopId Virtual desktop identifier. - * @param[in] monitor Monitor handle. - * @param[in] workAra Object representing single work area. - */ - void AddWorkArea(const GUID& desktopId, HMONITOR monitor, std::shared_ptr& workArea); - - /** - * Check if work area is already registered. - * - * @param[in] desktopId Virtual desktop identifier. - * @param[in] monitor Monitor handle. - * - * @returns Boolean indicating whether work area defined by virtual desktop id and monitor is already registered. - */ - bool IsNewWorkArea(const GUID& desktopId, HMONITOR monitor); - - /** - * Register changes in current virtual desktop layout. - * - * @param[in] active Array of currently active virtual desktop identifiers. - */ - void RegisterUpdates(const std::vector& active); - - /** - * Clear all persisted work area related data. - */ - void Clear(); - -private: - // Work area is uniquely defined by monitor and virtual desktop id. - std::unordered_map>> workAreaMap; -}; diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.cpp b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.cpp new file mode 100644 index 000000000000..089c28c90516 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.cpp @@ -0,0 +1,67 @@ +#include "pch.h" +#include "MonitorWorkAreaMap.h" + +#include + +WorkArea* const MonitorWorkAreaMap::GetWorkArea(HMONITOR monitor) const +{ + auto iter = m_workAreaMap.find(monitor); + if (iter != m_workAreaMap.end()) + { + return iter->second.get(); + } + + return nullptr; +} + +WorkArea* const MonitorWorkAreaMap::GetWorkAreaFromCursor() const +{ + const auto allMonitorsWorkArea = GetWorkArea(nullptr); + if (allMonitorsWorkArea) + { + // First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle) + return allMonitorsWorkArea; + } + else + { + // Otherwise, look for the work area based on cursor position + POINT cursorPoint; + if (!GetCursorPos(&cursorPoint)) + { + return nullptr; + } + + return GetWorkArea(MonitorFromPoint(cursorPoint, MONITOR_DEFAULTTONULL)); + } +} + +WorkArea* const MonitorWorkAreaMap::GetWorkAreaFromWindow(HWND window) const +{ + const auto allMonitorsWorkArea = GetWorkArea(nullptr); + if (allMonitorsWorkArea) + { + // First, check if there's a work area spanning all monitors (signalled by the NULL monitor handle) + return allMonitorsWorkArea; + } + else + { + // Otherwise, look for the work area based on the window's position + HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); + return GetWorkArea(monitor); + } +} + +const std::unordered_map>& MonitorWorkAreaMap::GetAllWorkAreas() const noexcept +{ + return m_workAreaMap; +} + +void MonitorWorkAreaMap::AddWorkArea(HMONITOR monitor, std::unique_ptr workArea) +{ + m_workAreaMap.insert({ monitor, std::move(workArea) }); +} + +void MonitorWorkAreaMap::Clear() noexcept +{ + m_workAreaMap.clear(); +} diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.h b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.h new file mode 100644 index 000000000000..10cb2dd0d6c7 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/MonitorWorkAreaMap.h @@ -0,0 +1,58 @@ +#pragma once + +#include "GuidUtils.h" + +class WorkArea; + +class MonitorWorkAreaMap +{ +public: + /** + * Get work area based on virtual desktop id and monitor handle. + * + * @param[in] monitor Monitor handle. + * + * @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). + */ + WorkArea* const GetWorkArea(HMONITOR monitor) const; + + /** + * Get work area based on virtual desktop id and 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). + */ + WorkArea* const GetWorkAreaFromCursor() const; + + /** + * Get work area on which specified window is located. + * + * @param[in] window Window handle. + * + * @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). + */ + WorkArea* const GetWorkAreaFromWindow(HWND window) const; + + /** + * @returns All registered work areas. + */ + const std::unordered_map>& GetAllWorkAreas() const noexcept; + + /** + * Register new work area. + * + * @param[in] monitor Monitor handle. + * @param[in] workAra Object representing single work area. + */ + void AddWorkArea(HMONITOR monitor, std::unique_ptr workArea); + + /** + * Clear all persisted work area related data. + */ + void Clear() noexcept; + +private: + std::unordered_map> m_workAreaMap; +}; diff --git a/src/modules/fancyzones/FancyZonesLib/WindowDrag.cpp b/src/modules/fancyzones/FancyZonesLib/WindowDrag.cpp index fe69251c96d9..c5c18d9fae51 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowDrag.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WindowDrag.cpp @@ -13,9 +13,10 @@ #include -WindowDrag::WindowDrag(HWND window, const std::unordered_map>& activeWorkAreas) : +WindowDrag::WindowDrag(HWND window, const std::unordered_map>& activeWorkAreas) : m_window(window), m_activeWorkAreas(activeWorkAreas), + m_currentWorkArea(nullptr), m_snappingMode(false) { m_windowProperties.hasNoVisibleOwner = !FancyZonesWindowUtils::HasVisibleOwner(m_window); @@ -28,7 +29,7 @@ WindowDrag::~WindowDrag() ResetWindowTransparency(); } -std::unique_ptr WindowDrag::Create(HWND window, const std::unordered_map>& activeWorkAreas) +std::unique_ptr WindowDrag::Create(HWND window, const std::unordered_map>& activeWorkAreas) { if (!FancyZonesWindowProcessing::IsProcessable(window) || !FancyZonesWindowUtils::IsCandidateForZoning(window) || @@ -57,7 +58,7 @@ bool WindowDrag::MoveSizeStart(HMONITOR monitor, bool isSnapping) if (isSnapping) { - m_currentWorkArea = iter->second; + m_currentWorkArea = iter->second.get(); } SwitchSnappingMode(isSnapping); @@ -72,7 +73,7 @@ void WindowDrag::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, bool is { // The drag has moved to a different monitor. // Change work area - if (iter->second != m_currentWorkArea) + if (iter->second.get() != m_currentWorkArea) { m_highlightedZones.Reset(); @@ -88,7 +89,7 @@ void WindowDrag::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, bool is } } - m_currentWorkArea = iter->second; + m_currentWorkArea = iter->second.get(); } if (m_currentWorkArea) @@ -169,18 +170,6 @@ void WindowDrag::SwitchSnappingMode(bool isSnapping) if (m_currentWorkArea) { m_currentWorkArea->UnsnapWindow(m_window); - FancyZonesWindowProperties::RemoveZoneIndexProperty(m_window); - - const auto& layout = m_currentWorkArea->GetLayout(); - if (layout) - { - auto guidStr = FancyZonesUtils::GuidToString(layout->Id()); - if (guidStr.has_value()) - { - AppZoneHistory::instance().RemoveAppLastZone(m_window, m_currentWorkArea->UniqueId(), guidStr.value()); - } - } - Trace::WorkArea::MoveOrResizeStarted(m_currentWorkArea->GetLayout().get(), m_currentWorkArea->GetLayoutWindows().get()); } } diff --git a/src/modules/fancyzones/FancyZonesLib/WindowDrag.h b/src/modules/fancyzones/FancyZonesLib/WindowDrag.h index 9e083980f35d..f45dc313f871 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowDrag.h +++ b/src/modules/fancyzones/FancyZonesLib/WindowDrag.h @@ -6,10 +6,10 @@ class WorkArea; class WindowDrag { - WindowDrag(HWND window, const std::unordered_map>& activeWorkAreas); + WindowDrag(HWND window, const std::unordered_map>& activeWorkAreas); public: - static std::unique_ptr Create(HWND window, const std::unordered_map>& activeWorkAreas); + static std::unique_ptr Create(HWND window, const std::unordered_map>& activeWorkAreas); ~WindowDrag(); bool MoveSizeStart(HMONITOR monitor, bool isSnapping); @@ -38,8 +38,8 @@ class WindowDrag const HWND m_window; WindowProperties m_windowProperties; // MoveSizeWindowInfo of the window at the moment when dragging started - const std::unordered_map>& m_activeWorkAreas; // all WorkAreas on current virtual desktop, mapped with monitors - std::shared_ptr m_currentWorkArea; // "Active" WorkArea, where the move/size is happening. Will update as drag moves between monitors. + const std::unordered_map>& m_activeWorkAreas; // all WorkAreas on current virtual desktop, mapped with monitors + WorkArea* m_currentWorkArea; // "Active" WorkArea, where the move/size is happening. Will update as drag moves between monitors. bool m_snappingMode{ false }; diff --git a/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp b/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp index 6efeb71bd6e0..ab71fbc7969e 100644 --- a/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WorkArea.cpp @@ -127,12 +127,12 @@ WorkArea::~WorkArea() windowPool.FreeZonesOverlayWindow(m_window); } -void WorkArea::MoveWindowIntoZoneByIndex(HWND window, ZoneIndex index) noexcept +void WorkArea::MoveWindowIntoZoneByIndex(HWND window, ZoneIndex index) { MoveWindowIntoZoneByIndexSet(window, { index }); } -void WorkArea::MoveWindowIntoZoneByIndexSet(HWND window, const ZoneIndexSet& indexSet, bool updatePosition /* = true*/) noexcept +void WorkArea::MoveWindowIntoZoneByIndexSet(HWND window, const ZoneIndexSet& indexSet, bool updatePosition /* = true*/) { if (!m_layout || !m_layoutWindows || m_layout->Zones().empty() || indexSet.empty()) { @@ -143,18 +143,15 @@ void WorkArea::MoveWindowIntoZoneByIndexSet(HWND window, const ZoneIndexSet& ind if (updatePosition) { - auto rect = m_layout->GetCombinedZonesRect(indexSet); - auto adjustedRect = FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(window, rect, m_window); + const auto rect = m_layout->GetCombinedZonesRect(indexSet); + const auto adjustedRect = FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(window, rect, m_window); FancyZonesWindowUtils::SizeWindowToRect(window, adjustedRect); } - m_layoutWindows->Assign(window, indexSet); - FancyZonesWindowProperties::StampZoneIndexProperty(window, indexSet); - - SaveWindowProcessToZoneIndex(window); + SnapWindow(window, indexSet); } -bool WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) noexcept +bool WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) { if (!m_layout || !m_layoutWindows || m_layout->Zones().empty()) { @@ -162,7 +159,7 @@ bool WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, } auto zoneIndexes = m_layoutWindows->GetZoneIndexSetFromWindow(window); - auto numZones = m_layout->Zones().size(); + const auto numZones = m_layout->Zones().size(); // The window was not assigned to any zone here if (zoneIndexes.size() == 0) @@ -171,7 +168,7 @@ bool WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, } else { - ZoneIndex oldId = zoneIndexes[0]; + const ZoneIndex oldId = zoneIndexes[0]; // We reached the edge if ((vkCode == VK_LEFT && oldId == 0) || (vkCode == VK_RIGHT && oldId == static_cast(numZones) - 1)) @@ -197,15 +194,10 @@ bool WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, } } - if (!FancyZonesWindowUtils::HasVisibleOwner(window)) - { - SaveWindowProcessToZoneIndex(window); - } - return true; } -bool WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) noexcept +bool WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) { if (!m_layout || !m_layoutWindows || m_layout->Zones().empty()) { @@ -216,7 +208,7 @@ bool WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCod std::vector usedZoneIndices(zones.size(), false); auto windowZones = m_layoutWindows->GetZoneIndexSetFromWindow(window); - for (ZoneIndex id : windowZones) + for (const ZoneIndex id : windowZones) { usedZoneIndices[id] = true; } @@ -250,7 +242,6 @@ bool WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCod if (result < zoneRects.size()) { MoveWindowIntoZoneByIndex(window, freeZoneIndices[result]); - SaveWindowProcessToZoneIndex(window); Trace::FancyZones::KeyboardSnapWindowToZone(m_layout.get(), m_layoutWindows.get()); return true; } @@ -266,7 +257,6 @@ bool WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCod if (result < zoneRects.size()) { MoveWindowIntoZoneByIndex(window, result); - SaveWindowProcessToZoneIndex(window); Trace::FancyZones::KeyboardSnapWindowToZone(m_layout.get(), m_layoutWindows.get()); return true; } @@ -275,7 +265,7 @@ bool WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCod return false; } -bool WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept +bool WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) { if (!m_layout || !m_layoutWindows || m_layout->Zones().empty()) { @@ -307,7 +297,7 @@ bool WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noe } else { - for (ZoneIndex idx : appliedZones) + for (const ZoneIndex idx : appliedZones) { usedZoneIndices[idx] = true; } @@ -327,7 +317,7 @@ bool WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noe } } - auto result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects); + const auto result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects); if (result < zoneRects.size()) { ZoneIndex targetZone = freeZoneIndices[result]; @@ -357,14 +347,13 @@ bool WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noe resultIndexSet = m_layout->GetCombinedZoneRange(extendModeData->windowInitialIndexSet[window], { targetZone }); } - auto rect = m_layout->GetCombinedZonesRect(resultIndexSet); - auto adjustedRect = FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(window, rect, m_window); + const auto rect = m_layout->GetCombinedZonesRect(resultIndexSet); + const auto adjustedRect = FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(window, rect, m_window); FancyZonesWindowUtils::SizeWindowToRect(window, adjustedRect); m_layoutWindows->Extend(window, resultIndexSet); - FancyZonesWindowProperties::StampZoneIndexProperty(window, resultIndexSet); - SaveWindowProcessToZoneIndex(window); + SnapWindow(window, resultIndexSet); return true; } @@ -372,39 +361,43 @@ bool WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noe return false; } -void WorkArea::SaveWindowProcessToZoneIndex(HWND window) noexcept +void WorkArea::SnapWindow(HWND window, const ZoneIndexSet& zones) { - if (m_layout && m_layoutWindows) + if (!m_layoutWindows || !m_layout) { - auto zoneIndexSet = m_layoutWindows->GetZoneIndexSetFromWindow(window); - if (zoneIndexSet.size()) - { - auto guidStr = FancyZonesUtils::GuidToString(m_layout->Id()); - if (guidStr.has_value()) - { - AppZoneHistory::instance().SetAppLastZones(window, m_uniqueId, guidStr.value(), zoneIndexSet); - } - } + return; } + + m_layoutWindows->Assign(window, zones); + + auto guidStr = FancyZonesUtils::GuidToString(m_layout->Id()); + if (guidStr.has_value()) + { + AppZoneHistory::instance().SetAppLastZones(window, m_uniqueId, guidStr.value(), zones); + } + + FancyZonesWindowProperties::StampZoneIndexProperty(window, zones); } -bool WorkArea::UnsnapWindow(HWND window) noexcept +void WorkArea::UnsnapWindow(HWND window) { - if (!m_layoutWindows) + if (!m_layoutWindows || !m_layout) { - return false; + return; } - if (!m_layoutWindows->GetZoneIndexSetFromWindow(window).empty()) + m_layoutWindows->Dismiss(window); + + auto guidStr = FancyZonesUtils::GuidToString(m_layout->Id()); + if (guidStr.has_value()) { - m_layoutWindows->Dismiss(window); - return true; + AppZoneHistory::instance().RemoveAppLastZone(window, m_uniqueId, guidStr.value()); } - return false; + FancyZonesWindowProperties::RemoveZoneIndexProperty(window); } -ZoneIndexSet WorkArea::GetWindowZoneIndexes(HWND window) const noexcept +ZoneIndexSet WorkArea::GetWindowZoneIndexes(HWND window) const { if (m_layout) { @@ -454,9 +447,9 @@ void WorkArea::FlashZones() } } -void WorkArea::UpdateActiveZoneSet() noexcept +void WorkArea::UpdateActiveZoneSet() { - bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId); + const bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId); if (!isLayoutAlreadyApplied) { AppliedLayouts::instance().ApplyDefaultLayout(m_uniqueId); @@ -469,7 +462,7 @@ void WorkArea::UpdateActiveZoneSet() noexcept } } -void WorkArea::CycleWindows(HWND window, bool reverse) noexcept +void WorkArea::CycleWindows(HWND window, bool reverse) { if (m_layoutWindows) { @@ -479,7 +472,7 @@ void WorkArea::CycleWindows(HWND window, bool reverse) noexcept #pragma region private -bool WorkArea::InitWindow(HINSTANCE hinstance) noexcept +bool WorkArea::InitWindow(HINSTANCE hinstance) { m_window = windowPool.NewZonesOverlayWindow(m_workAreaRect, hinstance, this); if (!m_window) @@ -492,11 +485,11 @@ bool WorkArea::InitWindow(HINSTANCE hinstance) noexcept return true; } -void WorkArea::InitLayout(const FancyZonesDataTypes::WorkAreaId& parentUniqueId) noexcept +void WorkArea::InitLayout(const FancyZonesDataTypes::WorkAreaId& parentUniqueId) { - Logger::info(L"Initialize layout on {}", m_uniqueId.toString()); + Logger::info(L"Initialize layout on {}, work area rect = {}x{}", m_uniqueId.toString(), m_workAreaRect.width(), m_workAreaRect.height()); - bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId); + const bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId); if (!isLayoutAlreadyApplied) { if (parentUniqueId.virtualDesktopId != GUID_NULL) @@ -512,7 +505,37 @@ void WorkArea::InitLayout(const FancyZonesDataTypes::WorkAreaId& parentUniqueId) CalculateZoneSet(); } -void WorkArea::CalculateZoneSet() noexcept +void WorkArea::InitSnappedWindows() +{ + static bool updatePositionOnceOnStartFlag = true; + Logger::info(L"Init work area windows, update positions = {}", updatePositionOnceOnStartFlag); + + for (const auto& window : VirtualDesktop::instance().GetWindowsFromCurrentDesktop()) + { + auto zoneIndexSet = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window); + if (zoneIndexSet.size() == 0) + { + continue; + } + + if (!m_uniqueId.monitorId.monitor) // one work area across monitors + { + MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, updatePositionOnceOnStartFlag); + } + else + { + const auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL); + if (monitor && m_uniqueId.monitorId.monitor == monitor) + { + MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, updatePositionOnceOnStartFlag); + } + } + } + + updatePositionOnceOnStartFlag = false; +} + +void WorkArea::CalculateZoneSet() { const auto appliedLayout = AppliedLayouts::instance().GetDeviceLayout(m_uniqueId); if (!appliedLayout.has_value()) @@ -561,7 +584,7 @@ void WorkArea::SetWorkAreaWindowAsTopmost(HWND draggedWindow) noexcept HWND windowInsertAfter = draggedWindow ? draggedWindow : HWND_TOPMOST; - const UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE; + constexpr UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE; SetWindowPos(m_window, windowInsertAfter, 0, 0, 0, 0, flags); } diff --git a/src/modules/fancyzones/FancyZonesLib/WorkArea.h b/src/modules/fancyzones/FancyZonesLib/WorkArea.h index 5c6ddcb276b5..a273b3167572 100644 --- a/src/modules/fancyzones/FancyZonesLib/WorkArea.h +++ b/src/modules/fancyzones/FancyZonesLib/WorkArea.h @@ -3,17 +3,27 @@ #include #include #include -#include class ZonesOverlay; class WorkArea { -public: WorkArea(HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesUtils::Rect& workAreaRect); - ~WorkArea(); public: + ~WorkArea(); + + static std::unique_ptr Create(HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesDataTypes::WorkAreaId& parentUniqueId, const FancyZonesUtils::Rect& workAreaRect) + { + auto self = std::unique_ptr(new WorkArea(hinstance, uniqueId, workAreaRect)); + if (!self->Init(hinstance, parentUniqueId)) + { + return nullptr; + } + + return self; + } + inline bool Init([[maybe_unused]] HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& parentUniqueId) { #ifndef UNIT_TESTS @@ -23,42 +33,48 @@ class WorkArea } #endif InitLayout(parentUniqueId); + InitSnappedWindows(); + return true; } - + FancyZonesDataTypes::WorkAreaId UniqueId() const noexcept { return { m_uniqueId }; } const std::unique_ptr& GetLayout() const noexcept { return m_layout; } const std::unique_ptr& GetLayoutWindows() const noexcept { return m_layoutWindows; } const HWND GetWorkAreaWindow() const noexcept { return m_window; } - ZoneIndexSet GetWindowZoneIndexes(HWND window) const noexcept; + ZoneIndexSet GetWindowZoneIndexes(HWND window) const; + + void MoveWindowIntoZoneByIndex(HWND window, ZoneIndex index); + void MoveWindowIntoZoneByIndexSet(HWND window, const ZoneIndexSet& indexSet, bool updatePosition = true); + bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle); + bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle); + bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode); - void MoveWindowIntoZoneByIndex(HWND window, ZoneIndex index) noexcept; - void MoveWindowIntoZoneByIndexSet(HWND window, const ZoneIndexSet& indexSet, bool updatePosition = true) noexcept; - bool MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle) noexcept; - bool MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle) noexcept; - bool ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode) noexcept; - void SaveWindowProcessToZoneIndex(HWND window) noexcept; - bool UnsnapWindow(HWND window) noexcept; + void SnapWindow(HWND window, const ZoneIndexSet& zones); + void UnsnapWindow(HWND window); - void UpdateActiveZoneSet() noexcept; + void UpdateActiveZoneSet(); void ShowZonesOverlay(const ZoneIndexSet& highlight, HWND draggedWindow = nullptr); void HideZonesOverlay(); void FlashZones(); - void CycleWindows(HWND window, bool reverse) noexcept; + void CycleWindows(HWND window, bool reverse); protected: static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept; private: - bool InitWindow(HINSTANCE hinstance) noexcept; - void InitLayout(const FancyZonesDataTypes::WorkAreaId& parentUniqueId) noexcept; - void CalculateZoneSet() noexcept; - LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; + bool InitWindow(HINSTANCE hinstance); + void InitLayout(const FancyZonesDataTypes::WorkAreaId& parentUniqueId); + void InitSnappedWindows(); + + void CalculateZoneSet(); void SetWorkAreaWindowAsTopmost(HWND draggedWindow) noexcept; + LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; + const FancyZonesUtils::Rect m_workAreaRect{}; const FancyZonesDataTypes::WorkAreaId m_uniqueId; HWND m_window{}; // Hidden tool window used to represent current monitor desktop work area. @@ -66,14 +82,3 @@ class WorkArea std::unique_ptr m_layoutWindows; std::unique_ptr m_zonesOverlay; }; - -inline std::shared_ptr MakeWorkArea(HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesDataTypes::WorkAreaId& parentUniqueId, const FancyZonesUtils::Rect& workAreaRect) -{ - auto self = std::make_shared(hinstance, uniqueId, workAreaRect); - if (!self->Init(hinstance, parentUniqueId)) - { - return nullptr; - } - - return self; -} diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp index 242535f26df1..bbfd3cb15937 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/WorkArea.Spec.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "Util.h" @@ -20,7 +21,7 @@ namespace FancyZonesUnitTests TEST_CLASS (WorkAreaCreationUnitTests) { - FancyZonesDataTypes::WorkAreaId m_uniqueId; + FancyZonesDataTypes::WorkAreaId m_workAreaId; FancyZonesDataTypes::WorkAreaId m_emptyUniqueId; FancyZonesUtils::Rect m_workAreaRect{ RECT(0,0,1920,1080) }; @@ -29,10 +30,10 @@ namespace FancyZonesUnitTests TEST_METHOD_INITIALIZE(Init) noexcept { - m_uniqueId.monitorId.deviceId.id = L"DELA026"; - m_uniqueId.monitorId.deviceId.instanceId = L"5&10a58c63&0&UID16777488"; - m_uniqueId.monitorId.serialNumber = L"serial-number"; - m_uniqueId.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value(); + m_workAreaId.monitorId.deviceId.id = L"DELA026"; + m_workAreaId.monitorId.deviceId.instanceId = L"5&10a58c63&0&UID16777488"; + m_workAreaId.monitorId.serialNumber = L"serial-number"; + m_workAreaId.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value(); AppZoneHistory::instance().LoadData(); AppliedLayouts::instance().LoadData(); @@ -51,9 +52,9 @@ namespace FancyZonesUnitTests { const auto defaultLayout = DefaultLayouts::instance().GetDefaultLayout(); - auto workArea = MakeWorkArea({}, m_uniqueId, m_emptyUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create({}, m_workAreaId, m_emptyUniqueId, m_workAreaRect); Assert::IsFalse(workArea == nullptr); - Assert::IsTrue(m_uniqueId == workArea->UniqueId()); + Assert::IsTrue(m_workAreaId == workArea->UniqueId()); const auto& layout = workArea->GetLayout(); Assert::IsNotNull(layout.get()); @@ -66,9 +67,9 @@ namespace FancyZonesUnitTests { const auto defaultLayout = DefaultLayouts::instance().GetDefaultLayout(); - auto workArea = MakeWorkArea({}, m_uniqueId, m_emptyUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create({}, m_workAreaId, m_emptyUniqueId, m_workAreaRect); Assert::IsFalse(workArea == nullptr); - Assert::IsTrue(m_uniqueId == workArea->UniqueId()); + Assert::IsTrue(m_workAreaId == workArea->UniqueId()); const auto& layout = workArea->GetLayout(); Assert::IsNotNull(layout.get()); @@ -96,15 +97,15 @@ namespace FancyZonesUnitTests .sensitivityRadius = 20, }; - auto parentWorkArea = MakeWorkArea(m_hInst, parentUniqueId, m_emptyUniqueId, m_workAreaRect); + auto parentWorkArea = WorkArea::Create(m_hInst, parentUniqueId, m_emptyUniqueId, m_workAreaRect); AppliedLayouts::instance().ApplyLayout(parentUniqueId, layout); - auto actualWorkArea = MakeWorkArea(m_hInst, m_uniqueId, parentUniqueId, m_workAreaRect); + auto actualWorkArea = WorkArea::Create(m_hInst, m_workAreaId, parentUniqueId, m_workAreaRect); Assert::IsNotNull(actualWorkArea->GetLayout().get()); Assert::IsNotNull(actualWorkArea->GetLayoutWindows().get()); - Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().contains(m_uniqueId)); - const auto& actualLayout = AppliedLayouts::instance().GetAppliedLayoutMap().at(m_uniqueId); + Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().contains(m_workAreaId)); + const auto& actualLayout = AppliedLayouts::instance().GetAppliedLayoutMap().at(m_workAreaId); Assert::AreEqual(static_cast(layout.type), static_cast(actualLayout.type)); Assert::AreEqual(FancyZonesUtils::GuidToString(layout.uuid).value(), FancyZonesUtils::GuidToString(actualLayout.uuid).value()); @@ -132,9 +133,9 @@ namespace FancyZonesUnitTests DefaultLayouts::instance().LoadData(); // test - auto workArea = MakeWorkArea({}, m_uniqueId, m_emptyUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create({}, m_workAreaId, m_emptyUniqueId, m_workAreaRect); Assert::IsFalse(workArea == nullptr); - Assert::IsTrue(m_uniqueId == workArea->UniqueId()); + Assert::IsTrue(m_workAreaId == workArea->UniqueId()); Assert::IsNotNull(workArea->GetLayout().get()); @@ -165,9 +166,9 @@ namespace FancyZonesUnitTests DefaultLayouts::instance().LoadData(); // test - auto workArea = MakeWorkArea({}, m_uniqueId, m_emptyUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create({}, m_workAreaId, m_emptyUniqueId, m_workAreaRect); Assert::IsFalse(workArea == nullptr); - Assert::IsTrue(m_uniqueId == workArea->UniqueId()); + Assert::IsTrue(m_workAreaId == workArea->UniqueId()); Assert::IsNotNull(workArea->GetLayout().get()); @@ -178,134 +179,10 @@ namespace FancyZonesUnitTests } }; - TEST_CLASS (WorkAreaUnitTests) - { - FancyZonesDataTypes::WorkAreaId m_uniqueId; - FancyZonesDataTypes::WorkAreaId m_parentUniqueId; // default empty - FancyZonesUtils::Rect m_workAreaRect{ RECT(0, 0, 1920, 1080) }; - - HINSTANCE m_hInst{}; - - TEST_METHOD_INITIALIZE(Init) noexcept - { - m_uniqueId.monitorId.deviceId.id = L"DELA026"; - m_uniqueId.monitorId.deviceId.instanceId = L"5&10a58c63&0&UID16777488"; - m_uniqueId.monitorId.serialNumber = L"serial-number"; - m_uniqueId.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value(); - - AppZoneHistory::instance().LoadData(); - AppliedLayouts::instance().LoadData(); - } - - TEST_METHOD_CLEANUP(CleanUp) noexcept - { - std::filesystem::remove(AppZoneHistory::AppZoneHistoryFileName()); - std::filesystem::remove(AppliedLayouts::AppliedLayoutsFileName()); - } - - public: - TEST_METHOD (SaveWindowProcessToZoneIndexNullptrWindow) - { - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); - - workArea->SaveWindowProcessToZoneIndex(nullptr); - - const auto actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory(); - Assert::IsTrue(actualAppZoneHistory.empty()); - } - - TEST_METHOD (SaveWindowProcessToZoneIndexNoWindowAdded) - { - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); - - auto window = Mocks::WindowCreate(m_hInst); - workArea->GetLayout()->Init(RECT{ 0, 0, 1920, 1080 }, Mocks::Monitor()); - - workArea->SaveWindowProcessToZoneIndex(window); - - const auto actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory(); - Assert::IsTrue(actualAppZoneHistory.empty()); - } - - TEST_METHOD (SaveWindowProcessToZoneIndexNoWindowAddedWithFilledAppZoneHistory) - { - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); - - const auto window = Mocks::WindowCreate(m_hInst); - const auto processPath = get_process_path(window); - const auto deviceId = workArea->UniqueId(); - const auto& layoutId = workArea->GetLayout()->Id(); - - // fill app zone history map - Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, Helpers::GuidToString(layoutId), { 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.at(0).zoneIndexSet); - - // add zone without window - workArea->GetLayout()->Init(RECT{ 0, 0, 1920, 1080 }, Mocks::Monitor()); - - workArea->SaveWindowProcessToZoneIndex(window); - 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.at(0).zoneIndexSet); - } - - TEST_METHOD (SaveWindowProcessToZoneIndexWindowAdded) - { - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); - - auto window = Mocks::WindowCreate(m_hInst); - const auto processPath = get_process_path(window); - const auto deviceId = workArea->UniqueId(); - const auto& layoutId = workArea->GetLayout()->Id(); - - workArea->MoveWindowIntoZoneByIndex(window, 0); - - //fill app zone history map - Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, Helpers::GuidToString(layoutId), { 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.at(0).zoneIndexSet); - - workArea->SaveWindowProcessToZoneIndex(window); - - const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory(); - Assert::AreEqual((size_t)1, actualAppZoneHistory.size()); - const auto& expected = workArea->GetLayoutWindows()->GetZoneIndexSetFromWindow(window); - const auto& actual = appHistoryArray.at(0).zoneIndexSet; - Assert::IsTrue(expected == actual); - } - - TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt) - { - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); - - auto window = Mocks::WindowCreate(m_hInst); - - const int originalWidth = 450; - const int originalHeight = 550; - - SetWindowPos(window, nullptr, 150, 150, originalWidth, originalHeight, SWP_SHOWWINDOW); - SetWindowLong(window, GWL_STYLE, GetWindowLong(window, GWL_STYLE) & ~WS_SIZEBOX); - - workArea->GetLayout()->Init(RECT{ 0, 0, 1920, 1080 }, Mocks::Monitor()); - workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true); - - RECT inZoneRect; - GetWindowRect(window, &inZoneRect); - Assert::AreEqual(originalWidth, (int)inZoneRect.right - (int)inZoneRect.left); - Assert::AreEqual(originalHeight, (int)inZoneRect.bottom - (int)inZoneRect.top); - } - }; - TEST_CLASS (WorkAreaMoveWindowUnitTests) { const std::wstring m_virtualDesktopIdStr = L"{A998CA86-F08D-4BCA-AED8-77F5C8FC9925}"; - const FancyZonesDataTypes::WorkAreaId m_uniqueId{ + const FancyZonesDataTypes::WorkAreaId m_workAreaId{ .monitorId = { .monitor = Mocks::Monitor(), .deviceId = { @@ -338,10 +215,10 @@ namespace FancyZonesUnitTests layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(0)); json::JsonObject workAreaId{}; - workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorID, json::value(m_uniqueId.monitorId.deviceId.id)); - workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorInstanceID, json::value(m_uniqueId.monitorId.deviceId.instanceId)); - workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorSerialNumberID, json::value(m_uniqueId.monitorId.serialNumber)); - workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorNumberID, json::value(m_uniqueId.monitorId.deviceId.number)); + workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorID, json::value(m_workAreaId.monitorId.deviceId.id)); + workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorInstanceID, json::value(m_workAreaId.monitorId.deviceId.instanceId)); + workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorSerialNumberID, json::value(m_workAreaId.monitorId.serialNumber)); + workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorNumberID, json::value(m_workAreaId.monitorId.deviceId.number)); workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::VirtualDesktopID, json::value(m_virtualDesktopIdStr)); json::JsonObject obj{}; @@ -372,10 +249,10 @@ namespace FancyZonesUnitTests layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(20)); json::JsonObject workAreaId{}; - workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorID, json::value(m_uniqueId.monitorId.deviceId.id)); - workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorInstanceID, json::value(m_uniqueId.monitorId.deviceId.instanceId)); - workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorSerialNumberID, json::value(m_uniqueId.monitorId.serialNumber)); - workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorNumberID, json::value(m_uniqueId.monitorId.deviceId.number)); + workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorID, json::value(m_workAreaId.monitorId.deviceId.id)); + workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorInstanceID, json::value(m_workAreaId.monitorId.deviceId.instanceId)); + workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorSerialNumberID, json::value(m_workAreaId.monitorId.serialNumber)); + workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorNumberID, json::value(m_workAreaId.monitorId.deviceId.number)); workAreaId.SetNamedValue(NonLocalizable::AppliedLayoutsIds::VirtualDesktopID, json::value(m_virtualDesktopIdStr)); json::JsonObject obj{}; @@ -407,7 +284,7 @@ namespace FancyZonesUnitTests { // prepare PrepareEmptyLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); // test @@ -424,7 +301,7 @@ namespace FancyZonesUnitTests { // prepare PrepareEmptyLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); // test @@ -441,7 +318,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); // test @@ -458,7 +335,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); // test @@ -475,7 +352,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); const auto& layoutWindows = workArea->GetLayoutWindows(); @@ -494,7 +371,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -512,7 +389,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -530,7 +407,7 @@ namespace FancyZonesUnitTests { // prepare PrepareEmptyLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); // test @@ -547,7 +424,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); // test @@ -564,7 +441,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); // test @@ -581,7 +458,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -599,7 +476,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -617,7 +494,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -635,7 +512,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -653,7 +530,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); const auto& layoutWindows = workArea->GetLayoutWindows(); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -672,7 +549,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -690,7 +567,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -708,7 +585,7 @@ namespace FancyZonesUnitTests { // prepare PrepareGridLayout(); - auto workArea = MakeWorkArea(m_hInst, m_uniqueId, m_parentUniqueId, m_workAreaRect); + auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); const auto window = Mocks::WindowCreate(m_hInst); workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true); // apply to 1st zone @@ -721,5 +598,86 @@ namespace FancyZonesUnitTests const auto& layoutWindows = workArea->GetLayoutWindows(); Assert::IsTrue(ZoneIndexSet{ 0, 2 } == layoutWindows->GetZoneIndexSetFromWindow(window)); } + + TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt) + { + const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); + const auto window = Mocks::WindowCreate(m_hInst); + + constexpr int originalWidth = 450; + constexpr int originalHeight = 550; + + SetWindowPos(window, nullptr, 150, 150, originalWidth, originalHeight, SWP_SHOWWINDOW); + SetWindowLong(window, GWL_STYLE, GetWindowLong(window, GWL_STYLE) & ~WS_SIZEBOX); + + workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true); + + RECT inZoneRect; + GetWindowRect(window, &inZoneRect); + + Assert::AreEqual(originalWidth, (int)inZoneRect.right - (int)inZoneRect.left); + Assert::AreEqual(originalHeight, (int)inZoneRect.bottom - (int)inZoneRect.top); + } + + TEST_METHOD (SnapWindowPropertyTest) + { + const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); + const auto window = Mocks::WindowCreate(m_hInst); + + const ZoneIndexSet expected = { 1, 2 }; + workArea->SnapWindow(window, expected); + + const auto actual = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window); + Assert::AreEqual(expected.size(), actual.size()); + for (int i = 0; i < expected.size(); i++) + { + Assert::AreEqual(expected.at(i), actual.at(i)); + } + } + + TEST_METHOD (SnapAppZoneHistoryTest) + { + const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); + const auto window = Mocks::WindowCreate(m_hInst); + + const ZoneIndexSet expected = { 1, 2 }; + workArea->SnapWindow(window, expected); + + const auto processPath = get_process_path(window); + const auto history = AppZoneHistory::instance().GetZoneHistory(processPath, m_workAreaId); + + Assert::IsTrue(history.has_value()); + Assert::AreEqual(expected.size(), history->zoneIndexSet.size()); + for (int i = 0; i < expected.size(); i++) + { + Assert::AreEqual(expected.at(i), history->zoneIndexSet.at(i)); + } + } + + TEST_METHOD (UnsnapPropertyTest) + { + const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); + const auto window = Mocks::WindowCreate(m_hInst); + + workArea->SnapWindow(window, { 1, 2 }); + workArea->UnsnapWindow(window); + + const auto actual = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window); + Assert::IsTrue(actual.empty()); + } + + TEST_METHOD (UnsnapAppZoneHistoryTest) + { + const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect); + const auto window = Mocks::WindowCreate(m_hInst); + + workArea->SnapWindow(window, { 1, 2 }); + workArea->UnsnapWindow(window); + + const auto processPath = get_process_path(window); + const auto history = AppZoneHistory::instance().GetZoneHistory(processPath, m_workAreaId); + + Assert::IsFalse(history.has_value()); + } }; }