[FancyZones] Improve code quality (part 5: work area initialization) (#23671)

This commit is contained in:
Seraphima Zykova
2023-01-31 12:55:46 +03:00
committed by GitHub
parent c1c14b4f2e
commit fcd05f2f51
12 changed files with 469 additions and 627 deletions

View File

@@ -21,7 +21,7 @@
#include <FancyZonesLib/FancyZonesWindowProperties.h>
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
#include <FancyZonesLib/MonitorUtils.h>
#include <FancyZonesLib/MonitorWorkAreaHandler.h>
#include <FancyZonesLib/MonitorWorkAreaMap.h>
#include <FancyZonesLib/on_thread_executor.h>
#include <FancyZonesLib/Settings.h>
#include <FancyZonesLib/SettingsObserver.h>
@@ -129,17 +129,16 @@ private:
bool OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexcept;
bool OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept;
bool OnSnapHotkey(DWORD vkCode) noexcept;
bool ProcessDirectedSnapHotkey(HWND window, DWORD vkCode, bool cycle, std::shared_ptr<WorkArea> 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<std::shared_ptr<WorkArea>, ZoneIndexSet> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>>& workAreaMap) noexcept;
void MoveWindowIntoZone(HWND window, std::shared_ptr<WorkArea> workArea, const ZoneIndexSet& zoneIndexSet) noexcept;
std::pair<WorkArea*, ZoneIndexSet> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& 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 @@ private:
HWND m_window{};
std::unique_ptr<WindowDrag> 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<std::shared_ptr<WorkArea>, ZoneIndexSet> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>>& workAreaMap) noexcept
std::pair<WorkArea*, ZoneIndexSet> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& workAreas) noexcept
{
if (monitor)
for (const auto& [workAreaMonitor, workArea] : workAreas)
{
if (workAreaMap.contains(monitor))
if (workAreaMonitor == monitor && workArea)
{
auto workArea = workAreaMap.at(monitor);
return std::pair<std::shared_ptr<WorkArea>, ZoneIndexSet>{ workArea, workArea->GetWindowZoneIndexes(window) };
}
else
{
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<std::shared_ptr<WorkArea>, ZoneIndexSet>{ workArea, zoneIndexSet };
}
return std::pair<WorkArea*, ZoneIndexSet>{ workArea.get(), workArea->GetWindowZoneIndexes(window) };
}
}
return std::pair<std::shared_ptr<WorkArea>, ZoneIndexSet>{ nullptr, {} };
Logger::error(L"No work area for the currently active monitor.");
return std::pair<WorkArea*, ZoneIndexSet>{ nullptr, {} };
}
void FancyZones::MoveWindowIntoZone(HWND window, std::shared_ptr<WorkArea> 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<std::shared_ptr<WorkArea>, 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)
{
movedToAppLastZone = MoveToAppLastZone(window, active, primary);
if (moveToAppLastZone)
{
movedToAppLastZone = MoveToAppLastZone(window, nullptr, nullptr);
}
}
else
{
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> 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<HMONITOR> FancyZones::GetMonitorsSorted() noexcept
std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
{
std::vector<std::pair<HMONITOR, RECT>> 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);

View File

@@ -59,7 +59,7 @@
<ClInclude Include="LayoutAssignedWindows.h" />
<ClInclude Include="ModuleConstants.h" />
<ClInclude Include="MonitorUtils.h" />
<ClInclude Include="MonitorWorkAreaHandler.h" />
<ClInclude Include="MonitorWorkAreaMap.h" />
<ClInclude Include="NotificationUtil.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="Generated Files/resource.h" />
@@ -113,7 +113,7 @@
<ClCompile Include="LayoutConfigurator.cpp" />
<ClCompile Include="LayoutAssignedWindows.cpp" />
<ClCompile Include="MonitorUtils.cpp" />
<ClCompile Include="MonitorWorkAreaHandler.cpp" />
<ClCompile Include="MonitorWorkAreaMap.cpp" />
<ClCompile Include="OnThreadExecutor.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>

View File

@@ -54,7 +54,7 @@
<ClInclude Include="SecondaryMouseButtonsHook.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MonitorWorkAreaHandler.h">
<ClInclude Include="MonitorWorkAreaMap.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GenericKeyHook.h">
@@ -197,7 +197,7 @@
<ClCompile Include="SecondaryMouseButtonsHook.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MonitorWorkAreaHandler.cpp">
<ClCompile Include="MonitorWorkAreaMap.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FancyZonesData.cpp">

View File

@@ -1,141 +0,0 @@
#include "pch.h"
#include "MonitorWorkAreaHandler.h"
#include "VirtualDesktop.h"
#include "WorkArea.h"
#include "util.h"
#include <common/logger/logger.h>
std::shared_ptr<WorkArea> 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<WorkArea> 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<WorkArea> 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<HMONITOR, std::shared_ptr<WorkArea>>& MonitorWorkAreaHandler::GetWorkAreasByDesktopId(const GUID& desktopId)
{
if (workAreaMap.contains(desktopId))
{
return workAreaMap[desktopId];
}
static const std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>> empty{};
return empty;
}
std::vector<std::shared_ptr<WorkArea>> MonitorWorkAreaHandler::GetAllWorkAreas()
{
std::vector<std::shared_ptr<WorkArea>> 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>& 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<GUID>& active)
{
std::unordered_set<GUID> 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();
}

View File

@@ -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<WorkArea> 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<WorkArea> 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<WorkArea> 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<HMONITOR, std::shared_ptr<WorkArea>>& GetWorkAreasByDesktopId(const GUID& desktopId);
/**
* @returns All registered work areas.
*/
std::vector<std::shared_ptr<WorkArea>> 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>& 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<GUID>& 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<GUID, std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>>> workAreaMap;
};

View File

@@ -0,0 +1,67 @@
#include "pch.h"
#include "MonitorWorkAreaMap.h"
#include <FancyZonesLib/WorkArea.h>
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<HMONITOR, std::unique_ptr<WorkArea>>& MonitorWorkAreaMap::GetAllWorkAreas() const noexcept
{
return m_workAreaMap;
}
void MonitorWorkAreaMap::AddWorkArea(HMONITOR monitor, std::unique_ptr<WorkArea> workArea)
{
m_workAreaMap.insert({ monitor, std::move(workArea) });
}
void MonitorWorkAreaMap::Clear() noexcept
{
m_workAreaMap.clear();
}

View File

@@ -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<HMONITOR, std::unique_ptr<WorkArea>>& 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> workArea);
/**
* Clear all persisted work area related data.
*/
void Clear() noexcept;
private:
std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>> m_workAreaMap;
};

View File

@@ -13,9 +13,10 @@
#include <common/utils/elevation.h>
WindowDrag::WindowDrag(HWND window, const std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>>& activeWorkAreas) :
WindowDrag::WindowDrag(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& 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> WindowDrag::Create(HWND window, const std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>>& activeWorkAreas)
std::unique_ptr<WindowDrag> WindowDrag::Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& 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());
}
}

View File

@@ -6,10 +6,10 @@ class WorkArea;
class WindowDrag
{
WindowDrag(HWND window, const std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>>& activeWorkAreas);
WindowDrag(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);
public:
static std::unique_ptr<WindowDrag> Create(HWND window, const std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>>& activeWorkAreas);
static std::unique_ptr<WindowDrag> Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);
~WindowDrag();
bool MoveSizeStart(HMONITOR monitor, bool isSnapping);
@@ -38,8 +38,8 @@ private:
const HWND m_window;
WindowProperties m_windowProperties; // MoveSizeWindowInfo of the window at the moment when dragging started
const std::unordered_map<HMONITOR, std::shared_ptr<WorkArea>>& m_activeWorkAreas; // all WorkAreas on current virtual desktop, mapped with monitors
std::shared_ptr<WorkArea> m_currentWorkArea; // "Active" WorkArea, where the move/size is happening. Will update as drag moves between monitors.
const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& 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 };

View File

@@ -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<int64_t>(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<bool> 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);
}

View File

@@ -3,17 +3,27 @@
#include <FancyZonesLib/FancyZonesDataTypes.h>
#include <FancyZonesLib/Layout.h>
#include <FancyZonesLib/LayoutAssignedWindows.h>
#include <FancyZonesLib/util.h>
class ZonesOverlay;
class WorkArea
{
public:
WorkArea(HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesUtils::Rect& workAreaRect);
~WorkArea();
public:
~WorkArea();
static std::unique_ptr<WorkArea> Create(HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesDataTypes::WorkAreaId& parentUniqueId, const FancyZonesUtils::Rect& workAreaRect)
{
auto self = std::unique_ptr<WorkArea>(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 @@ public:
}
#endif
InitLayout(parentUniqueId);
InitSnappedWindows();
return true;
}
FancyZonesDataTypes::WorkAreaId UniqueId() const noexcept { return { m_uniqueId }; }
const std::unique_ptr<Layout>& GetLayout() const noexcept { return m_layout; }
const std::unique_ptr<LayoutAssignedWindows>& 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) 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 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 UpdateActiveZoneSet() noexcept;
void SnapWindow(HWND window, const ZoneIndexSet& zones);
void UnsnapWindow(HWND window);
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 @@ private:
std::unique_ptr<LayoutAssignedWindows> m_layoutWindows;
std::unique_ptr<ZonesOverlay> m_zonesOverlay;
};
inline std::shared_ptr<WorkArea> MakeWorkArea(HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesDataTypes::WorkAreaId& parentUniqueId, const FancyZonesUtils::Rect& workAreaRect)
{
auto self = std::make_shared<WorkArea>(hinstance, uniqueId, workAreaRect);
if (!self->Init(hinstance, parentUniqueId))
{
return nullptr;
}
return self;
}

View File

@@ -6,6 +6,7 @@
#include <FancyZonesLib/FancyZonesData/AppliedLayouts.h>
#include <FancyZonesLib/FancyZonesData/AppZoneHistory.h>
#include <FancyZonesLib/FancyZonesData/DefaultLayouts.h>
#include <FancyZonesLib/FancyZonesWindowProperties.h>
#include <FancyZonesLib/LayoutAssignedWindows.h>
#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<int>(layout.type), static_cast<int>(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<ZoneIndex>{ 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<ZoneIndex>{ 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<ZoneIndex>{ 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());
}
};
}