mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
[FancyZones] Improve code quality (part 6) (#28034)
This commit is contained in:
@@ -26,7 +26,8 @@
|
|||||||
#include <FancyZonesLib/Settings.h>
|
#include <FancyZonesLib/Settings.h>
|
||||||
#include <FancyZonesLib/SettingsObserver.h>
|
#include <FancyZonesLib/SettingsObserver.h>
|
||||||
#include <FancyZonesLib/trace.h>
|
#include <FancyZonesLib/trace.h>
|
||||||
#include <FancyZonesLib/WindowDrag.h>
|
#include <FancyZonesLib/WindowKeyboardSnap.h>
|
||||||
|
#include <FancyZonesLib/WindowMouseSnap.h>
|
||||||
#include <FancyZonesLib/WorkArea.h>
|
#include <FancyZonesLib/WorkArea.h>
|
||||||
|
|
||||||
enum class DisplayChangeType
|
enum class DisplayChangeType
|
||||||
@@ -142,10 +143,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void UpdateWorkAreas(bool updateWindowPositions) noexcept;
|
void UpdateWorkAreas(bool updateWindowPositions) noexcept;
|
||||||
void CycleWindows(bool reverse) noexcept;
|
void CycleWindows(bool reverse) noexcept;
|
||||||
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, WorkArea* const workArea) noexcept;
|
|
||||||
|
|
||||||
void SyncVirtualDesktops() noexcept;
|
void SyncVirtualDesktops() noexcept;
|
||||||
|
|
||||||
@@ -153,13 +150,11 @@ private:
|
|||||||
|
|
||||||
bool MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept;
|
bool MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept;
|
||||||
|
|
||||||
void UpdateActiveLayouts() noexcept;
|
void RefreshLayouts() noexcept;
|
||||||
bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept;
|
bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept;
|
||||||
void ApplyQuickLayout(int key) noexcept;
|
void ApplyQuickLayout(int key) noexcept;
|
||||||
void FlashZones() noexcept;
|
void FlashZones() noexcept;
|
||||||
|
|
||||||
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
|
|
||||||
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
|
|
||||||
HMONITOR WorkAreaKeyFromWindow(HWND window) noexcept;
|
HMONITOR WorkAreaKeyFromWindow(HWND window) noexcept;
|
||||||
|
|
||||||
virtual void SettingsUpdate(SettingId type) override;
|
virtual void SettingsUpdate(SettingId type) override;
|
||||||
@@ -167,7 +162,8 @@ private:
|
|||||||
const HINSTANCE m_hinstance{};
|
const HINSTANCE m_hinstance{};
|
||||||
|
|
||||||
HWND m_window{};
|
HWND m_window{};
|
||||||
std::unique_ptr<WindowDrag> m_windowDrag{};
|
std::unique_ptr<WindowMouseSnap> m_windowMouseSnapper{};
|
||||||
|
WindowKeyboardSnap m_windowKeyboardSnapper{};
|
||||||
MonitorWorkAreaMap m_workAreaHandler;
|
MonitorWorkAreaMap m_workAreaHandler;
|
||||||
DraggingState m_draggingState;
|
DraggingState m_draggingState;
|
||||||
|
|
||||||
@@ -288,8 +284,8 @@ FancyZones::VirtualDesktopChanged() noexcept
|
|||||||
|
|
||||||
void FancyZones::MoveSizeStart(HWND window, HMONITOR monitor)
|
void FancyZones::MoveSizeStart(HWND window, HMONITOR monitor)
|
||||||
{
|
{
|
||||||
m_windowDrag = WindowDrag::Create(window, m_workAreaHandler.GetAllWorkAreas());
|
m_windowMouseSnapper = WindowMouseSnap::Create(window, m_workAreaHandler.GetAllWorkAreas());
|
||||||
if (m_windowDrag)
|
if (m_windowMouseSnapper)
|
||||||
{
|
{
|
||||||
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
||||||
{
|
{
|
||||||
@@ -298,13 +294,13 @@ void FancyZones::MoveSizeStart(HWND window, HMONITOR monitor)
|
|||||||
|
|
||||||
m_draggingState.Enable();
|
m_draggingState.Enable();
|
||||||
m_draggingState.UpdateDraggingState();
|
m_draggingState.UpdateDraggingState();
|
||||||
m_windowDrag->MoveSizeStart(monitor, m_draggingState.IsDragging());
|
m_windowMouseSnapper->MoveSizeStart(monitor, m_draggingState.IsDragging());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyZones::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen)
|
void FancyZones::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen)
|
||||||
{
|
{
|
||||||
if (m_windowDrag)
|
if (m_windowMouseSnapper)
|
||||||
{
|
{
|
||||||
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
||||||
{
|
{
|
||||||
@@ -312,17 +308,17 @@ void FancyZones::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_draggingState.UpdateDraggingState();
|
m_draggingState.UpdateDraggingState();
|
||||||
m_windowDrag->MoveSizeUpdate(monitor, ptScreen, m_draggingState.IsDragging(), m_draggingState.IsSelectManyZonesState());
|
m_windowMouseSnapper->MoveSizeUpdate(monitor, ptScreen, m_draggingState.IsDragging(), m_draggingState.IsSelectManyZonesState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyZones::MoveSizeEnd()
|
void FancyZones::MoveSizeEnd()
|
||||||
{
|
{
|
||||||
if (m_windowDrag)
|
if (m_windowMouseSnapper)
|
||||||
{
|
{
|
||||||
m_windowDrag->MoveSizeEnd();
|
m_windowMouseSnapper->MoveSizeEnd();
|
||||||
m_draggingState.Disable();
|
m_draggingState.Disable();
|
||||||
m_windowDrag = nullptr;
|
m_windowMouseSnapper = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,7 +335,7 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept
|
|||||||
workArea = workAreas.at(monitor).get();
|
workArea = workAreas.at(monitor).get();
|
||||||
if (workArea)
|
if (workArea)
|
||||||
{
|
{
|
||||||
indexes = workArea->GetWindowZoneIndexes(window);
|
indexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workArea->UniqueId(), workArea->GetLayoutId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -353,7 +349,7 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept
|
|||||||
{
|
{
|
||||||
if (secondaryWorkArea)
|
if (secondaryWorkArea)
|
||||||
{
|
{
|
||||||
indexes = secondaryWorkArea->GetWindowZoneIndexes(window);
|
indexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, secondaryWorkArea->UniqueId(), secondaryWorkArea->GetLayoutId());
|
||||||
workArea = secondaryWorkArea.get();
|
workArea = secondaryWorkArea.get();
|
||||||
if (!indexes.empty())
|
if (!indexes.empty())
|
||||||
{
|
{
|
||||||
@@ -365,8 +361,8 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept
|
|||||||
|
|
||||||
if (!indexes.empty() && workArea)
|
if (!indexes.empty() && workArea)
|
||||||
{
|
{
|
||||||
Trace::FancyZones::SnapNewWindowIntoZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
|
Trace::FancyZones::SnapNewWindowIntoZone(workArea->GetLayout().get(), workArea->GetLayoutWindows());
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, indexes);
|
workArea->Snap(window, indexes);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -604,7 +600,40 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
|||||||
|
|
||||||
if (message == WM_PRIV_SNAP_HOTKEY)
|
if (message == WM_PRIV_SNAP_HOTKEY)
|
||||||
{
|
{
|
||||||
OnSnapHotkey(static_cast<DWORD>(lparam));
|
// We already checked in ShouldProcessSnapHotkey whether the foreground window is a candidate for zoning
|
||||||
|
auto foregroundWindow = GetForegroundWindow();
|
||||||
|
|
||||||
|
HMONITOR monitor{ nullptr };
|
||||||
|
if (!FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
||||||
|
{
|
||||||
|
monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTONULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FancyZonesSettings::settings().moveWindowsBasedOnPosition)
|
||||||
|
{
|
||||||
|
auto monitors = FancyZonesUtils::GetAllMonitorRects<&MONITORINFOEX::rcWork>();
|
||||||
|
RECT windowRect;
|
||||||
|
if (GetWindowRect(foregroundWindow, &windowRect))
|
||||||
|
{
|
||||||
|
// Check whether Alt is used in the shortcut key combination
|
||||||
|
if (GetAsyncKeyState(VK_MENU) & 0x8000)
|
||||||
|
{
|
||||||
|
m_windowKeyboardSnapper.Extend(foregroundWindow, windowRect, monitor, static_cast<DWORD>(lparam), m_workAreaHandler.GetAllWorkAreas());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_windowKeyboardSnapper.Snap(foregroundWindow, windowRect, monitor, static_cast<DWORD>(lparam), m_workAreaHandler.GetAllWorkAreas(), monitors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::error("Error snapping window by keyboard shortcut: failed to get window rect");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_windowKeyboardSnapper.Snap(foregroundWindow, monitor, static_cast<DWORD>(lparam), m_workAreaHandler.GetAllWorkAreas(), FancyZonesUtils::GetMonitorsOrdered());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (message == WM_PRIV_INIT)
|
else if (message == WM_PRIV_INIT)
|
||||||
{
|
{
|
||||||
@@ -661,7 +690,7 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
|
|||||||
else if (message == WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE)
|
else if (message == WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE)
|
||||||
{
|
{
|
||||||
AppliedLayouts::instance().LoadData();
|
AppliedLayouts::instance().LoadData();
|
||||||
UpdateActiveLayouts();
|
RefreshLayouts();
|
||||||
}
|
}
|
||||||
else if (message == WM_PRIV_DEFAULT_LAYOUTS_FILE_UPDATE)
|
else if (message == WM_PRIV_DEFAULT_LAYOUTS_FILE_UPDATE)
|
||||||
{
|
{
|
||||||
@@ -800,7 +829,7 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept
|
|||||||
{
|
{
|
||||||
for (const auto& [window, zones] : windowsToSnap)
|
for (const auto& [window, zones] : windowsToSnap)
|
||||||
{
|
{
|
||||||
workArea->SnapWindow(window, zones, false);
|
workArea->Snap(window, zones, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -813,9 +842,9 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept
|
|||||||
const auto zones = iter->second;
|
const auto zones = iter->second;
|
||||||
const auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
const auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||||
const auto workAreaForMonitor = m_workAreaHandler.GetWorkArea(monitor);
|
const auto workAreaForMonitor = m_workAreaHandler.GetWorkArea(monitor);
|
||||||
if (workAreaForMonitor && workAreaForMonitor->GetWindowZoneIndexes(window) == zones)
|
if (workAreaForMonitor && AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaForMonitor->UniqueId(), workAreaForMonitor->GetLayoutId()) == zones)
|
||||||
{
|
{
|
||||||
workAreaForMonitor->SnapWindow(window, zones, false);
|
workAreaForMonitor->Snap(window, zones, false);
|
||||||
iter = windowsToSnap.erase(iter);
|
iter = windowsToSnap.erase(iter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -829,10 +858,10 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept
|
|||||||
{
|
{
|
||||||
for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas())
|
for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas())
|
||||||
{
|
{
|
||||||
const auto savedIndexes = workArea->GetWindowZoneIndexes(window);
|
const auto savedIndexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workArea->UniqueId(), workArea->GetLayoutId());
|
||||||
if (savedIndexes == zones)
|
if (savedIndexes == zones)
|
||||||
{
|
{
|
||||||
workArea->SnapWindow(window, zones, false);
|
workArea->Snap(window, zones, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -862,257 +891,6 @@ void FancyZones::CycleWindows(bool reverse) noexcept
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FancyZones::OnSnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode) noexcept
|
|
||||||
{
|
|
||||||
HMONITOR current = WorkAreaKeyFromWindow(window);
|
|
||||||
|
|
||||||
std::vector<HMONITOR> monitorInfo = GetMonitorsSorted();
|
|
||||||
if (current && monitorInfo.size() > 1 && FancyZonesSettings::settings().moveWindowAcrossMonitors)
|
|
||||||
{
|
|
||||||
// Multi monitor environment.
|
|
||||||
auto currMonitorInfo = std::find(std::begin(monitorInfo), std::end(monitorInfo), current);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
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())
|
|
||||||
{
|
|
||||||
if (prevWorkArea && workArea != prevWorkArea.get())
|
|
||||||
{
|
|
||||||
prevWorkArea->UnsnapWindow(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// We iterated through all zones in current monitor zone layout, move on to next one (or previous depending on direction).
|
|
||||||
if (vkCode == VK_RIGHT)
|
|
||||||
{
|
|
||||||
currMonitorInfo = std::next(currMonitorInfo);
|
|
||||||
if (currMonitorInfo == std::end(monitorInfo))
|
|
||||||
{
|
|
||||||
currMonitorInfo = std::begin(monitorInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (vkCode == VK_LEFT)
|
|
||||||
{
|
|
||||||
if (currMonitorInfo == std::begin(monitorInfo))
|
|
||||||
{
|
|
||||||
currMonitorInfo = std::end(monitorInfo);
|
|
||||||
}
|
|
||||||
currMonitorInfo = std::prev(currMonitorInfo);
|
|
||||||
}
|
|
||||||
} while (*currMonitorInfo != current);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto workArea = m_workAreaHandler.GetWorkArea(current);
|
|
||||||
// Single monitor environment, or combined multi-monitor environment.
|
|
||||||
if (FancyZonesSettings::settings().restoreSize)
|
|
||||||
{
|
|
||||||
bool moved = workArea && workArea->MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, false /* cycle through zones */);
|
|
||||||
if (!moved)
|
|
||||||
{
|
|
||||||
FancyZonesWindowUtils::RestoreWindowOrigin(window);
|
|
||||||
FancyZonesWindowUtils::RestoreWindowSize(window);
|
|
||||||
}
|
|
||||||
else if (workArea)
|
|
||||||
{
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
|
|
||||||
}
|
|
||||||
return moved;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool moved = workArea && workArea->MoveWindowIntoZoneByDirectionAndIndex(window, vkCode, true /* cycle through zones */);
|
|
||||||
|
|
||||||
if (moved)
|
|
||||||
{
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return moved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FancyZones::OnSnapHotkeyBasedOnPosition(HWND window, DWORD vkCode) noexcept
|
|
||||||
{
|
|
||||||
HMONITOR current = WorkAreaKeyFromWindow(window);
|
|
||||||
|
|
||||||
auto allMonitors = FancyZonesUtils::GetAllMonitorRects<&MONITORINFOEX::rcWork>();
|
|
||||||
|
|
||||||
if (current && allMonitors.size() > 1 && FancyZonesSettings::settings().moveWindowAcrossMonitors)
|
|
||||||
{
|
|
||||||
// Multi monitor environment.
|
|
||||||
// First, try to stay on the same monitor
|
|
||||||
bool success = ProcessDirectedSnapHotkey(window, vkCode, false, m_workAreaHandler.GetWorkArea(current));
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If that didn't work, extract zones from all other monitors and target one of them
|
|
||||||
std::vector<RECT> zoneRects;
|
|
||||||
std::vector<std::pair<ZoneIndex, WorkArea*>> zoneRectsInfo;
|
|
||||||
RECT currentMonitorRect{ .top = 0, .bottom = -1 };
|
|
||||||
|
|
||||||
for (const auto& [monitor, monitorRect] : allMonitors)
|
|
||||||
{
|
|
||||||
if (monitor == current)
|
|
||||||
{
|
|
||||||
currentMonitorRect = monitorRect;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto workArea = m_workAreaHandler.GetWorkArea(monitor);
|
|
||||||
if (workArea)
|
|
||||||
{
|
|
||||||
const auto& layout = workArea->GetLayout();
|
|
||||||
if (layout)
|
|
||||||
{
|
|
||||||
const auto& zones = layout->Zones();
|
|
||||||
for (const auto& [zoneId, zone] : zones)
|
|
||||||
{
|
|
||||||
RECT zoneRect = zone.GetZoneRect();
|
|
||||||
|
|
||||||
zoneRect.left += monitorRect.left;
|
|
||||||
zoneRect.right += monitorRect.left;
|
|
||||||
zoneRect.top += monitorRect.top;
|
|
||||||
zoneRect.bottom += monitorRect.top;
|
|
||||||
|
|
||||||
zoneRects.emplace_back(zoneRect);
|
|
||||||
zoneRectsInfo.emplace_back(zoneId, workArea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure we can get the windowRect, if not, just quit
|
|
||||||
RECT windowRect;
|
|
||||||
if (!GetWindowRect(window, &windowRect))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto chosenIdx = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
|
||||||
|
|
||||||
if (chosenIdx < zoneRects.size())
|
|
||||||
{
|
|
||||||
// Moving to another monitor succeeded
|
|
||||||
const auto& [trueZoneIdx, workArea] = zoneRectsInfo[chosenIdx];
|
|
||||||
if (workArea)
|
|
||||||
{
|
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, { trueZoneIdx });
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We reached the end of all monitors.
|
|
||||||
// Try again, cycling on all monitors.
|
|
||||||
// First, add zones from the origin monitor to zoneRects
|
|
||||||
// Sanity check: the current monitor is valid
|
|
||||||
if (currentMonitorRect.top <= currentMonitorRect.bottom)
|
|
||||||
{
|
|
||||||
auto workArea = m_workAreaHandler.GetWorkArea(current);
|
|
||||||
if (workArea)
|
|
||||||
{
|
|
||||||
const auto& layout = workArea->GetLayout();
|
|
||||||
if (layout)
|
|
||||||
{
|
|
||||||
const auto& zones = layout->Zones();
|
|
||||||
for (const auto& [zoneId, zone] : zones)
|
|
||||||
{
|
|
||||||
RECT zoneRect = zone.GetZoneRect();
|
|
||||||
|
|
||||||
zoneRect.left += currentMonitorRect.left;
|
|
||||||
zoneRect.right += currentMonitorRect.left;
|
|
||||||
zoneRect.top += currentMonitorRect.top;
|
|
||||||
zoneRect.bottom += currentMonitorRect.top;
|
|
||||||
|
|
||||||
zoneRects.emplace_back(zoneRect);
|
|
||||||
zoneRectsInfo.emplace_back(zoneId, workArea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT combinedRect = FancyZonesUtils::GetAllMonitorsCombinedRect<&MONITORINFOEX::rcWork>();
|
|
||||||
windowRect = FancyZonesUtils::PrepareRectForCycling(windowRect, combinedRect, vkCode);
|
|
||||||
chosenIdx = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
|
||||||
if (chosenIdx < zoneRects.size())
|
|
||||||
{
|
|
||||||
// Moving to another monitor succeeded
|
|
||||||
const auto& [trueZoneIdx, workArea] = zoneRectsInfo[chosenIdx];
|
|
||||||
|
|
||||||
if (workArea)
|
|
||||||
{
|
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, { trueZoneIdx });
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Giving up
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Single monitor environment, or combined multi-monitor environment.
|
|
||||||
return ProcessDirectedSnapHotkey(window, vkCode, true, m_workAreaHandler.GetWorkArea(current));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
|
|
||||||
{
|
|
||||||
// We already checked in ShouldProcessSnapHotkey whether the foreground window is a candidate for zoning
|
|
||||||
auto window = GetForegroundWindow();
|
|
||||||
if (FancyZonesSettings::settings().moveWindowsBasedOnPosition)
|
|
||||||
{
|
|
||||||
return OnSnapHotkeyBasedOnPosition(window, vkCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (vkCode == VK_LEFT || vkCode == VK_RIGHT) && OnSnapHotkeyBasedOnZoneNumber(window, vkCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
bool result = workArea && workArea->ExtendWindowByDirectionAndPosition(window, vkCode);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool result = workArea && workArea->MoveWindowIntoZoneByDirectionAndPosition(window, vkCode, cycle);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FancyZones::SyncVirtualDesktops() noexcept
|
void FancyZones::SyncVirtualDesktops() noexcept
|
||||||
{
|
{
|
||||||
auto guids = VirtualDesktop::instance().GetVirtualDesktopIdsFromRegistry();
|
auto guids = VirtualDesktop::instance().GetVirtualDesktopIdsFromRegistry();
|
||||||
@@ -1186,13 +964,13 @@ void FancyZones::SettingsUpdate(SettingId id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyZones::UpdateActiveLayouts() noexcept
|
void FancyZones::RefreshLayouts() noexcept
|
||||||
{
|
{
|
||||||
for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas())
|
for (const auto& [_, workArea] : m_workAreaHandler.GetAllWorkAreas())
|
||||||
{
|
{
|
||||||
if (workArea)
|
if (workArea)
|
||||||
{
|
{
|
||||||
workArea->UpdateActiveZoneSet();
|
workArea->InitLayout();
|
||||||
|
|
||||||
if (FancyZonesSettings::settings().zoneSetChange_moveWindows)
|
if (FancyZonesSettings::settings().zoneSetChange_moveWindows)
|
||||||
{
|
{
|
||||||
@@ -1265,7 +1043,7 @@ void FancyZones::ApplyQuickLayout(int key) noexcept
|
|||||||
{
|
{
|
||||||
AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), layout.value());
|
AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), layout.value());
|
||||||
AppliedLayouts::instance().SaveData();
|
AppliedLayouts::instance().SaveData();
|
||||||
UpdateActiveLayouts();
|
RefreshLayouts();
|
||||||
FlashZones();
|
FlashZones();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1284,32 +1062,6 @@ void FancyZones::FlashZones() noexcept
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<HMONITOR> FancyZones::GetMonitorsSorted() noexcept
|
|
||||||
{
|
|
||||||
auto monitorInfo = GetRawMonitorData();
|
|
||||||
FancyZonesUtils::OrderMonitors(monitorInfo);
|
|
||||||
std::vector<HMONITOR> output;
|
|
||||||
std::transform(std::begin(monitorInfo), std::end(monitorInfo), std::back_inserter(output), [](const auto& info) { return info.first; });
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::pair<HMONITOR, RECT>> FancyZones::GetRawMonitorData() noexcept
|
|
||||||
{
|
|
||||||
std::vector<std::pair<HMONITOR, RECT>> monitorInfo;
|
|
||||||
const auto& activeWorkAreaMap = m_workAreaHandler.GetAllWorkAreas();
|
|
||||||
for (const auto& [monitor, workArea] : activeWorkAreaMap)
|
|
||||||
{
|
|
||||||
if (workArea && workArea->GetLayout() != nullptr)
|
|
||||||
{
|
|
||||||
MONITORINFOEX mi;
|
|
||||||
mi.cbSize = sizeof(mi);
|
|
||||||
GetMonitorInfo(monitor, &mi);
|
|
||||||
monitorInfo.push_back({ monitor, mi.rcMonitor });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return monitorInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
HMONITOR FancyZones::WorkAreaKeyFromWindow(HWND window) noexcept
|
HMONITOR FancyZones::WorkAreaKeyFromWindow(HWND window) noexcept
|
||||||
{
|
{
|
||||||
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
|
||||||
|
|||||||
@@ -103,13 +103,14 @@ namespace JsonUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.workAreaId = deviceIdOpt.value();
|
data.workAreaId = deviceIdOpt.value();
|
||||||
data.zoneSetUuid = json.GetNamedString(NonLocalizable::AppZoneHistoryIds::LayoutIdID);
|
std::wstring layoutIdStr = json.GetNamedString(NonLocalizable::AppZoneHistoryIds::LayoutIdID).c_str();
|
||||||
|
auto layoutIdOpt = FancyZonesUtils::GuidFromString(layoutIdStr);
|
||||||
if (!FancyZonesUtils::IsValidGuid(data.zoneSetUuid))
|
if (!layoutIdOpt.has_value())
|
||||||
{
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.layoutId = layoutIdOpt.value();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +188,11 @@ namespace JsonUtils
|
|||||||
|
|
||||||
desktopData.SetNamedValue(NonLocalizable::AppZoneHistoryIds::LayoutIndexesID, jsonIndexSet);
|
desktopData.SetNamedValue(NonLocalizable::AppZoneHistoryIds::LayoutIndexesID, jsonIndexSet);
|
||||||
desktopData.SetNamedValue(NonLocalizable::AppZoneHistoryIds::DeviceID, device);
|
desktopData.SetNamedValue(NonLocalizable::AppZoneHistoryIds::DeviceID, device);
|
||||||
desktopData.SetNamedValue(NonLocalizable::AppZoneHistoryIds::LayoutIdID, json::value(data.zoneSetUuid));
|
auto layoutIdStr = FancyZonesUtils::GuidToString(data.layoutId);
|
||||||
|
if (layoutIdStr)
|
||||||
|
{
|
||||||
|
desktopData.SetNamedValue(NonLocalizable::AppZoneHistoryIds::LayoutIdID, json::value(layoutIdStr.value()));
|
||||||
|
}
|
||||||
|
|
||||||
appHistoryArray.Append(desktopData);
|
appHistoryArray.Append(desktopData);
|
||||||
}
|
}
|
||||||
@@ -334,7 +339,7 @@ void AppZoneHistory::AdjustWorkAreaIds(const std::vector<FancyZonesDataTypes::Mo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet)
|
bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const GUID& layoutId, const ZoneIndexSet& zoneIndexSet)
|
||||||
{
|
{
|
||||||
if (IsAnotherWindowOfApplicationInstanceZoned(window, workAreaId))
|
if (IsAnotherWindowOfApplicationInstanceZoned(window, workAreaId))
|
||||||
{
|
{
|
||||||
@@ -347,7 +352,11 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Wor
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::info(L"Add app zone history, device: {}, layout: {}", workAreaId.toString(), zoneSetId);
|
auto layoutIdStr = FancyZonesUtils::GuidToString(layoutId);
|
||||||
|
if (layoutIdStr)
|
||||||
|
{
|
||||||
|
Logger::info(L"Add app zone history, device: {}, layout: {}", workAreaId.toString(), layoutIdStr.value());
|
||||||
|
}
|
||||||
|
|
||||||
DWORD processId = 0;
|
DWORD processId = 0;
|
||||||
GetWindowThreadProcessId(window, &processId);
|
GetWindowThreadProcessId(window, &processId);
|
||||||
@@ -362,7 +371,7 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Wor
|
|||||||
{
|
{
|
||||||
// application already has history on this work area, update it with new window position
|
// application already has history on this work area, update it with new window position
|
||||||
data.processIdToHandleMap[processId] = window;
|
data.processIdToHandleMap[processId] = window;
|
||||||
data.zoneSetUuid = zoneSetId;
|
data.layoutId = layoutId;
|
||||||
data.zoneIndexSet = zoneIndexSet;
|
data.zoneIndexSet = zoneIndexSet;
|
||||||
SaveData();
|
SaveData();
|
||||||
return true;
|
return true;
|
||||||
@@ -373,7 +382,7 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Wor
|
|||||||
std::unordered_map<DWORD, HWND> processIdToHandleMap{};
|
std::unordered_map<DWORD, HWND> processIdToHandleMap{};
|
||||||
processIdToHandleMap[processId] = window;
|
processIdToHandleMap[processId] = window;
|
||||||
FancyZonesDataTypes::AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap,
|
FancyZonesDataTypes::AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap,
|
||||||
.zoneSetUuid = zoneSetId,
|
.layoutId = layoutId,
|
||||||
.workAreaId = workAreaId,
|
.workAreaId = workAreaId,
|
||||||
.zoneIndexSet = zoneIndexSet };
|
.zoneIndexSet = zoneIndexSet };
|
||||||
|
|
||||||
@@ -392,56 +401,66 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Wor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring_view& zoneSetId)
|
bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const GUID& layoutId)
|
||||||
{
|
{
|
||||||
Logger::info(L"Remove app zone history, device: {}, layout: {}", workAreaId.toString(), zoneSetId);
|
|
||||||
|
|
||||||
auto processPath = get_process_path_waiting_uwp(window);
|
auto processPath = get_process_path_waiting_uwp(window);
|
||||||
if (!processPath.empty())
|
if (processPath.empty())
|
||||||
{
|
{
|
||||||
auto history = m_history.find(processPath);
|
return false;
|
||||||
if (history != std::end(m_history))
|
|
||||||
{
|
|
||||||
auto& perDesktopData = history->second;
|
|
||||||
for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);)
|
|
||||||
{
|
|
||||||
if (data->workAreaId == workAreaId && data->zoneSetUuid == zoneSetId)
|
|
||||||
{
|
|
||||||
if (!IsAnotherWindowOfApplicationInstanceZoned(window, workAreaId))
|
|
||||||
{
|
|
||||||
DWORD processId = 0;
|
|
||||||
GetWindowThreadProcessId(window, &processId);
|
|
||||||
|
|
||||||
data->processIdToHandleMap.erase(processId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is another instance of same application placed in the same zone don't erase history
|
|
||||||
auto windowZoneStamps = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
|
|
||||||
for (auto placedWindow : data->processIdToHandleMap)
|
|
||||||
{
|
|
||||||
auto placedWindowZoneStamps = FancyZonesWindowProperties::RetrieveZoneIndexProperty(placedWindow.second);
|
|
||||||
if (IsWindow(placedWindow.second) && (windowZoneStamps == placedWindowZoneStamps))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data = perDesktopData.erase(data);
|
|
||||||
if (perDesktopData.empty())
|
|
||||||
{
|
|
||||||
m_history.erase(processPath);
|
|
||||||
}
|
|
||||||
SaveData();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto history = m_history.find(processPath);
|
||||||
|
if (history == std::end(m_history))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto layoutIdStrOpt = FancyZonesUtils::GuidToString(layoutId);
|
||||||
|
if (!layoutIdStrOpt)
|
||||||
|
{
|
||||||
|
Logger::error("Invalid layout id");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::info(L"Remove app zone history, device: {}, layout: {}", workAreaId.toString(), layoutIdStrOpt.value());
|
||||||
|
|
||||||
|
auto& perDesktopData = history->second;
|
||||||
|
for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);)
|
||||||
|
{
|
||||||
|
if (data->workAreaId == workAreaId && data->layoutId == layoutId)
|
||||||
|
{
|
||||||
|
if (!IsAnotherWindowOfApplicationInstanceZoned(window, workAreaId))
|
||||||
|
{
|
||||||
|
DWORD processId = 0;
|
||||||
|
GetWindowThreadProcessId(window, &processId);
|
||||||
|
|
||||||
|
data->processIdToHandleMap.erase(processId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is another instance of same application placed in the same zone don't erase history
|
||||||
|
auto windowZoneStamps = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
|
||||||
|
for (auto placedWindow : data->processIdToHandleMap)
|
||||||
|
{
|
||||||
|
auto placedWindowZoneStamps = FancyZonesWindowProperties::RetrieveZoneIndexProperty(placedWindow.second);
|
||||||
|
if (IsWindow(placedWindow.second) && (windowZoneStamps == placedWindowZoneStamps))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data = perDesktopData.erase(data);
|
||||||
|
if (perDesktopData.empty())
|
||||||
|
{
|
||||||
|
m_history.erase(processPath);
|
||||||
|
}
|
||||||
|
SaveData();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++data;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +551,7 @@ bool AppZoneHistory::IsAnotherWindowOfApplicationInstanceZoned(HWND window, cons
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring& zoneSetId) const
|
ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const GUID& layoutId) const
|
||||||
{
|
{
|
||||||
auto processPath = get_process_path_waiting_uwp(window);
|
auto processPath = get_process_path_waiting_uwp(window);
|
||||||
if (processPath.empty())
|
if (processPath.empty())
|
||||||
@@ -559,7 +578,7 @@ ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZone
|
|||||||
const auto& perDesktopData = history->second;
|
const auto& perDesktopData = history->second;
|
||||||
for (const auto& data : perDesktopData)
|
for (const auto& data : perDesktopData)
|
||||||
{
|
{
|
||||||
if (data.zoneSetUuid == zoneSetId && data.workAreaId == workAreaId)
|
if (data.layoutId == layoutId && data.workAreaId == workAreaId)
|
||||||
{
|
{
|
||||||
if (data.workAreaId.virtualDesktopId == workAreaId.virtualDesktopId || data.workAreaId.virtualDesktopId == GUID_NULL)
|
if (data.workAreaId.virtualDesktopId == workAreaId.virtualDesktopId || data.workAreaId.virtualDesktopId == GUID_NULL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ public:
|
|||||||
void SaveData();
|
void SaveData();
|
||||||
void AdjustWorkAreaIds(const std::vector<FancyZonesDataTypes::MonitorId>& ids);
|
void AdjustWorkAreaIds(const std::vector<FancyZonesDataTypes::MonitorId>& ids);
|
||||||
|
|
||||||
bool SetAppLastZones(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet);
|
bool SetAppLastZones(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const GUID& layoutId, const ZoneIndexSet& zoneIndexSet);
|
||||||
bool RemoveAppLastZone(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring_view& zoneSetId);
|
bool RemoveAppLastZone(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const GUID& layoutId);
|
||||||
|
|
||||||
void RemoveApp(const std::wstring& appPath);
|
void RemoveApp(const std::wstring& appPath);
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ public:
|
|||||||
std::optional<FancyZonesDataTypes::AppZoneHistoryData> GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept;
|
std::optional<FancyZonesDataTypes::AppZoneHistoryData> GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept;
|
||||||
|
|
||||||
bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept;
|
bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept;
|
||||||
ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring& zoneSetId) const;
|
ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const GUID& layoutId) const;
|
||||||
|
|
||||||
void SyncVirtualDesktops();
|
void SyncVirtualDesktops();
|
||||||
void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops);
|
void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops);
|
||||||
|
|||||||
@@ -144,9 +144,9 @@ namespace FancyZonesDataTypes
|
|||||||
{
|
{
|
||||||
std::unordered_map<DWORD, HWND> processIdToHandleMap; // Maps process id(DWORD) of application to zoned window handle(HWND)
|
std::unordered_map<DWORD, HWND> processIdToHandleMap; // Maps process id(DWORD) of application to zoned window handle(HWND)
|
||||||
|
|
||||||
std::wstring zoneSetUuid;
|
GUID layoutId = {};
|
||||||
WorkAreaId workAreaId;
|
WorkAreaId workAreaId = {};
|
||||||
ZoneIndexSet zoneIndexSet;
|
ZoneIndexSet zoneIndexSet = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DeviceInfoData
|
struct DeviceInfoData
|
||||||
|
|||||||
@@ -71,7 +71,8 @@
|
|||||||
<ClInclude Include="trace.h" />
|
<ClInclude Include="trace.h" />
|
||||||
<ClInclude Include="util.h" />
|
<ClInclude Include="util.h" />
|
||||||
<ClInclude Include="VirtualDesktop.h" />
|
<ClInclude Include="VirtualDesktop.h" />
|
||||||
<ClInclude Include="WindowDrag.h" />
|
<ClInclude Include="WindowKeyboardSnap.h" />
|
||||||
|
<ClInclude Include="WindowMouseSnap.h" />
|
||||||
<ClInclude Include="FancyZonesWindowProperties.h" />
|
<ClInclude Include="FancyZonesWindowProperties.h" />
|
||||||
<ClInclude Include="WindowUtils.h" />
|
<ClInclude Include="WindowUtils.h" />
|
||||||
<ClInclude Include="Zone.h" />
|
<ClInclude Include="Zone.h" />
|
||||||
@@ -123,7 +124,8 @@
|
|||||||
<ClCompile Include="trace.cpp" />
|
<ClCompile Include="trace.cpp" />
|
||||||
<ClCompile Include="util.cpp" />
|
<ClCompile Include="util.cpp" />
|
||||||
<ClCompile Include="VirtualDesktop.cpp" />
|
<ClCompile Include="VirtualDesktop.cpp" />
|
||||||
<ClCompile Include="WindowDrag.cpp" />
|
<ClCompile Include="WindowKeyboardSnap.cpp" />
|
||||||
|
<ClCompile Include="WindowMouseSnap.cpp" />
|
||||||
<ClCompile Include="WindowUtils.cpp" />
|
<ClCompile Include="WindowUtils.cpp" />
|
||||||
<ClCompile Include="Zone.cpp" />
|
<ClCompile Include="Zone.cpp" />
|
||||||
<ClCompile Include="WorkArea.cpp" />
|
<ClCompile Include="WorkArea.cpp" />
|
||||||
|
|||||||
@@ -162,7 +162,10 @@
|
|||||||
<ClInclude Include="DraggingState.h">
|
<ClInclude Include="DraggingState.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="WindowDrag.h">
|
<ClInclude Include="WindowMouseSnap.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="WindowKeyboardSnap.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -263,7 +266,10 @@
|
|||||||
<ClCompile Include="DraggingState.cpp">
|
<ClCompile Include="DraggingState.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="WindowDrag.cpp">
|
<ClCompile Include="WindowMouseSnap.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="WindowKeyboardSnap.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace ZonedWindowProperties
|
|||||||
const wchar_t PropertySortKeyWithinZone[] = L"FancyZones_TabSortKeyWithinZone";
|
const wchar_t PropertySortKeyWithinZone[] = L"FancyZones_TabSortKeyWithinZone";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyZonesWindowProperties::StampZoneIndexProperty(HWND window, const ZoneIndexSet& zoneSet)
|
bool FancyZonesWindowProperties::StampZoneIndexProperty(HWND window, const ZoneIndexSet& zoneSet)
|
||||||
{
|
{
|
||||||
RemoveZoneIndexProperty(window);
|
RemoveZoneIndexProperty(window);
|
||||||
ZoneIndexSetBitmask bitmask = ZoneIndexSetBitmask::FromIndexSet(zoneSet);
|
ZoneIndexSetBitmask bitmask = ZoneIndexSetBitmask::FromIndexSet(zoneSet);
|
||||||
@@ -33,6 +33,7 @@ void FancyZonesWindowProperties::StampZoneIndexProperty(HWND window, const ZoneI
|
|||||||
if (!SetProp(window, ZonedWindowProperties::PropertyMultipleZone64ID, rawData))
|
if (!SetProp(window, ZonedWindowProperties::PropertyMultipleZone64ID, rawData))
|
||||||
{
|
{
|
||||||
Logger::error(L"Failed to stamp window {}", get_last_error_or_default(GetLastError()));
|
Logger::error(L"Failed to stamp window {}", get_last_error_or_default(GetLastError()));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,8 +50,11 @@ void FancyZonesWindowProperties::StampZoneIndexProperty(HWND window, const ZoneI
|
|||||||
if (!SetProp(window, ZonedWindowProperties::PropertyMultipleZone128ID, rawData))
|
if (!SetProp(window, ZonedWindowProperties::PropertyMultipleZone128ID, rawData))
|
||||||
{
|
{
|
||||||
Logger::error(L"Failed to stamp window {}", get_last_error_or_default(GetLastError()));
|
Logger::error(L"Failed to stamp window {}", get_last_error_or_default(GetLastError()));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FancyZonesWindowProperties::RemoveZoneIndexProperty(HWND window)
|
void FancyZonesWindowProperties::RemoveZoneIndexProperty(HWND window)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace ZonedWindowProperties
|
|||||||
|
|
||||||
namespace FancyZonesWindowProperties
|
namespace FancyZonesWindowProperties
|
||||||
{
|
{
|
||||||
void StampZoneIndexProperty(HWND window, const ZoneIndexSet& zoneSet);
|
bool StampZoneIndexProperty(HWND window, const ZoneIndexSet& zoneSet);
|
||||||
void RemoveZoneIndexProperty(HWND window);
|
void RemoveZoneIndexProperty(HWND window);
|
||||||
ZoneIndexSet RetrieveZoneIndexProperty(HWND window);
|
ZoneIndexSet RetrieveZoneIndexProperty(HWND window);
|
||||||
|
|
||||||
|
|||||||
@@ -277,13 +277,16 @@ namespace
|
|||||||
.monitorId = { .deviceId = MonitorUtils::Display::ConvertObsoleteDeviceId(deviceId->deviceName) },
|
.monitorId = { .deviceId = MonitorUtils::Display::ConvertObsoleteDeviceId(deviceId->deviceName) },
|
||||||
.virtualDesktopId = deviceId->virtualDesktopId
|
.virtualDesktopId = deviceId->virtualDesktopId
|
||||||
};
|
};
|
||||||
data.zoneSetUuid = json.GetNamedString(NonLocalizable::ZoneSetUuidStr);
|
|
||||||
|
|
||||||
if (!FancyZonesUtils::IsValidGuid(data.zoneSetUuid))
|
std::wstring layoutIdStr = json.GetNamedString(NonLocalizable::ZoneSetUuidStr).c_str();
|
||||||
|
auto layoutIdOpt = FancyZonesUtils::GuidFromString(layoutIdStr);
|
||||||
|
if (!layoutIdOpt.has_value())
|
||||||
{
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.layoutId = layoutIdOpt.value();
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,37 +6,10 @@
|
|||||||
#include <FancyZonesLib/VirtualDesktop.h>
|
#include <FancyZonesLib/VirtualDesktop.h>
|
||||||
#include <FancyZonesLib/WindowUtils.h>
|
#include <FancyZonesLib/WindowUtils.h>
|
||||||
|
|
||||||
LayoutAssignedWindows::LayoutAssignedWindows()
|
|
||||||
{
|
|
||||||
m_extendData = std::make_unique<ExtendWindowModeData>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LayoutAssignedWindows::Assign(HWND window, const ZoneIndexSet& zones)
|
void LayoutAssignedWindows::Assign(HWND window, const ZoneIndexSet& zones)
|
||||||
{
|
{
|
||||||
Dismiss(window);
|
Dismiss(window);
|
||||||
|
|
||||||
// clear info about extension
|
|
||||||
std::erase_if(m_extendData->windowInitialIndexSet, [window](const auto& item) { return item.first == window; });
|
|
||||||
std::erase_if(m_extendData->windowFinalIndex, [window](const auto& item) { return item.first == window; });
|
|
||||||
|
|
||||||
for (const auto& index : zones)
|
|
||||||
{
|
|
||||||
m_windowIndexSet[window].push_back(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FancyZonesSettings::settings().disableRoundCorners)
|
|
||||||
{
|
|
||||||
FancyZonesWindowUtils::DisableRoundCorners(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tabSortKeyWithinZone = FancyZonesWindowProperties::GetTabSortKeyWithinZone(window);
|
|
||||||
InsertWindowIntoZone(window, tabSortKeyWithinZone, zones);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LayoutAssignedWindows::Extend(HWND window, const ZoneIndexSet& zones)
|
|
||||||
{
|
|
||||||
Dismiss(window);
|
|
||||||
|
|
||||||
for (const auto& index : zones)
|
for (const auto& index : zones)
|
||||||
{
|
{
|
||||||
m_windowIndexSet[window].push_back(index);
|
m_windowIndexSet[window].push_back(index);
|
||||||
@@ -133,11 +106,6 @@ void LayoutAssignedWindows::CycleWindows(HWND window, bool reverse)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unique_ptr<LayoutAssignedWindows::ExtendWindowModeData>& LayoutAssignedWindows::ExtendWindowData()
|
|
||||||
{
|
|
||||||
return m_extendData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LayoutAssignedWindows::InsertWindowIntoZone(HWND window, std::optional<size_t> tabSortKeyWithinZone, const ZoneIndexSet& indexSet)
|
void LayoutAssignedWindows::InsertWindowIntoZone(HWND window, std::optional<size_t> tabSortKeyWithinZone, const ZoneIndexSet& indexSet)
|
||||||
{
|
{
|
||||||
if (tabSortKeyWithinZone.has_value())
|
if (tabSortKeyWithinZone.has_value())
|
||||||
|
|||||||
@@ -4,19 +4,11 @@
|
|||||||
|
|
||||||
class LayoutAssignedWindows
|
class LayoutAssignedWindows
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
struct ExtendWindowModeData
|
|
||||||
{
|
|
||||||
std::map<HWND, ZoneIndexSet> windowInitialIndexSet;
|
|
||||||
std::map<HWND, ZoneIndex> windowFinalIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
LayoutAssignedWindows();
|
LayoutAssignedWindows() = default;
|
||||||
~LayoutAssignedWindows() = default;
|
~LayoutAssignedWindows() = default;
|
||||||
|
|
||||||
void Assign(HWND window, const ZoneIndexSet& zones);
|
void Assign(HWND window, const ZoneIndexSet& zones);
|
||||||
void Extend(HWND window, const ZoneIndexSet& zones);
|
|
||||||
void Dismiss(HWND window);
|
void Dismiss(HWND window);
|
||||||
|
|
||||||
std::map<HWND, ZoneIndexSet> SnappedWindows() const noexcept;
|
std::map<HWND, ZoneIndexSet> SnappedWindows() const noexcept;
|
||||||
@@ -25,12 +17,9 @@ public :
|
|||||||
|
|
||||||
void CycleWindows(HWND window, bool reverse);
|
void CycleWindows(HWND window, bool reverse);
|
||||||
|
|
||||||
const std::unique_ptr<ExtendWindowModeData>& ExtendWindowData();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<HWND, ZoneIndexSet> m_windowIndexSet{};
|
std::map<HWND, ZoneIndexSet> m_windowIndexSet{};
|
||||||
std::map<ZoneIndexSet, std::vector<HWND>> m_windowsByIndexSets{};
|
std::map<ZoneIndexSet, std::vector<HWND>> m_windowsByIndexSets{};
|
||||||
std::unique_ptr<ExtendWindowModeData> m_extendData{}; // Needed for ExtendWindowByDirectionAndPosition
|
|
||||||
|
|
||||||
void InsertWindowIntoZone(HWND window, std::optional<size_t> tabSortKeyWithinZone, const ZoneIndexSet& indexSet);
|
void InsertWindowIntoZone(HWND window, std::optional<size_t> tabSortKeyWithinZone, const ZoneIndexSet& indexSet);
|
||||||
HWND GetNextZoneWindow(ZoneIndexSet indexSet, HWND current, bool reverse) noexcept;
|
HWND GetNextZoneWindow(ZoneIndexSet indexSet, HWND current, bool reverse) noexcept;
|
||||||
|
|||||||
@@ -80,6 +80,13 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(UNIT_TESTS)
|
||||||
|
inline void SetSettings(const Settings& settings)
|
||||||
|
{
|
||||||
|
m_settings = settings;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void AddObserver(SettingsObserver& observer);
|
void AddObserver(SettingsObserver& observer);
|
||||||
void RemoveObserver(SettingsObserver& observer);
|
void RemoveObserver(SettingsObserver& observer);
|
||||||
|
|
||||||
|
|||||||
489
src/modules/fancyzones/FancyZonesLib/WindowKeyboardSnap.cpp
Normal file
489
src/modules/fancyzones/FancyZonesLib/WindowKeyboardSnap.cpp
Normal file
@@ -0,0 +1,489 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "WindowKeyboardSnap.h"
|
||||||
|
|
||||||
|
#include <FancyZonesLib/Settings.h>
|
||||||
|
#include <FancyZonesLib/trace.h>
|
||||||
|
#include <FancyZonesLib/WindowUtils.h>
|
||||||
|
#include <FancyZonesLib/WorkArea.h>
|
||||||
|
#include <FancyZonesLib/util.h>
|
||||||
|
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
|
||||||
|
bool WindowKeyboardSnap::Snap(HWND window, HMONITOR monitor, DWORD vkCode, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas, const std::vector<HMONITOR>& monitors)
|
||||||
|
{
|
||||||
|
return (vkCode == VK_LEFT || vkCode == VK_RIGHT) && SnapHotkeyBasedOnZoneNumber(window, vkCode, monitor, activeWorkAreas, monitors);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowKeyboardSnap::Snap(HWND window, RECT windowRect, HMONITOR monitor, DWORD vkCode, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas, const std::vector<std::pair<HMONITOR, RECT>>& monitors)
|
||||||
|
{
|
||||||
|
if (!activeWorkAreas.contains(monitor))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean previous extension data
|
||||||
|
m_extendData.Reset();
|
||||||
|
|
||||||
|
const auto& currentWorkArea = activeWorkAreas.at(monitor);
|
||||||
|
if (monitors.size() > 1 && FancyZonesSettings::settings().moveWindowAcrossMonitors)
|
||||||
|
{
|
||||||
|
// Multi monitor environment.
|
||||||
|
// First, try to stay on the same monitor
|
||||||
|
bool success = MoveByDirectionAndPosition(window, windowRect, vkCode, false, currentWorkArea.get());
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to snap on another monitor
|
||||||
|
success = SnapBasedOnPositionOnAnotherMonitor(window, windowRect, vkCode, monitor, activeWorkAreas, monitors);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// Unsnap from previous work area
|
||||||
|
currentWorkArea->Unsnap(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Single monitor environment, or combined multi-monitor environment.
|
||||||
|
return MoveByDirectionAndPosition(window, windowRect, vkCode, true, currentWorkArea.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowKeyboardSnap::Extend(HWND window, RECT windowRect, HMONITOR monitor, DWORD vkCode, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas)
|
||||||
|
{
|
||||||
|
if (!activeWorkAreas.contains(monitor))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue extension process
|
||||||
|
const auto& workArea = activeWorkAreas.at(monitor);
|
||||||
|
return Extend(window, windowRect, vkCode, workArea.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowKeyboardSnap::SnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode, HMONITOR current, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas, const std::vector<HMONITOR>& monitors)
|
||||||
|
{
|
||||||
|
// clean previous extension data
|
||||||
|
m_extendData.Reset();
|
||||||
|
|
||||||
|
if (current && monitors.size() > 1 && FancyZonesSettings::settings().moveWindowAcrossMonitors)
|
||||||
|
{
|
||||||
|
// Multi monitor environment.
|
||||||
|
auto currMonitor = std::find(std::begin(monitors), std::end(monitors), current);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (activeWorkAreas.contains(*currMonitor))
|
||||||
|
{
|
||||||
|
const auto& workArea = activeWorkAreas.at(*currMonitor);
|
||||||
|
|
||||||
|
if (MoveByDirectionAndIndex(window, vkCode, false /* cycle through zones */, workArea.get()))
|
||||||
|
{
|
||||||
|
// unassign from previous work area
|
||||||
|
for (auto& [_, prevWorkArea] : activeWorkAreas)
|
||||||
|
{
|
||||||
|
if (prevWorkArea && workArea != prevWorkArea)
|
||||||
|
{
|
||||||
|
prevWorkArea->Unsnap(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// We iterated through all zones in current monitor zone layout, move on to next one (or previous depending on direction).
|
||||||
|
if (vkCode == VK_RIGHT)
|
||||||
|
{
|
||||||
|
currMonitor = std::next(currMonitor);
|
||||||
|
if (currMonitor == std::end(monitors))
|
||||||
|
{
|
||||||
|
currMonitor = std::begin(monitors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (vkCode == VK_LEFT)
|
||||||
|
{
|
||||||
|
if (currMonitor == std::begin(monitors))
|
||||||
|
{
|
||||||
|
currMonitor = std::end(monitors);
|
||||||
|
}
|
||||||
|
currMonitor = std::prev(currMonitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (*currMonitor != current);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (activeWorkAreas.contains(current))
|
||||||
|
{
|
||||||
|
const auto& workArea = activeWorkAreas.at(current);
|
||||||
|
bool moved = MoveByDirectionAndIndex(window, vkCode, FancyZonesSettings::settings().moveWindowAcrossMonitors /* cycle through zones */, workArea.get());
|
||||||
|
|
||||||
|
if (FancyZonesSettings::settings().restoreSize && !moved)
|
||||||
|
{
|
||||||
|
FancyZonesWindowUtils::RestoreWindowOrigin(window);
|
||||||
|
FancyZonesWindowUtils::RestoreWindowSize(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
return moved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowKeyboardSnap::SnapBasedOnPositionOnAnotherMonitor(HWND window, RECT windowRect, DWORD vkCode, HMONITOR current, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas, const std::vector<std::pair<HMONITOR, RECT>>& monitors)
|
||||||
|
{
|
||||||
|
// Extract zones from all other monitors and target one of them
|
||||||
|
std::vector<RECT> zoneRects;
|
||||||
|
std::vector<std::pair<ZoneIndex, WorkArea*>> zoneRectsInfo;
|
||||||
|
RECT currentMonitorRect{ .top = 0, .bottom = -1 };
|
||||||
|
|
||||||
|
for (const auto& [monitor, monitorRect] : monitors)
|
||||||
|
{
|
||||||
|
if (monitor == current)
|
||||||
|
{
|
||||||
|
currentMonitorRect = monitorRect;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (activeWorkAreas.contains(monitor))
|
||||||
|
{
|
||||||
|
const auto& workArea = activeWorkAreas.at(monitor);
|
||||||
|
const auto& layout = workArea->GetLayout();
|
||||||
|
if (layout)
|
||||||
|
{
|
||||||
|
const auto& zones = layout->Zones();
|
||||||
|
for (const auto& [zoneId, zone] : zones)
|
||||||
|
{
|
||||||
|
RECT zoneRect = zone.GetZoneRect();
|
||||||
|
|
||||||
|
zoneRect.left += monitorRect.left;
|
||||||
|
zoneRect.right += monitorRect.left;
|
||||||
|
zoneRect.top += monitorRect.top;
|
||||||
|
zoneRect.bottom += monitorRect.top;
|
||||||
|
|
||||||
|
zoneRects.emplace_back(zoneRect);
|
||||||
|
zoneRectsInfo.emplace_back(zoneId, workArea.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chosenIdx = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
||||||
|
|
||||||
|
if (chosenIdx < zoneRects.size())
|
||||||
|
{
|
||||||
|
// Moving to another monitor succeeded
|
||||||
|
const auto& [trueZoneIdx, workArea] = zoneRectsInfo[chosenIdx];
|
||||||
|
bool snapped = false;
|
||||||
|
if (workArea)
|
||||||
|
{
|
||||||
|
snapped = workArea->Snap(window, { trueZoneIdx });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapped)
|
||||||
|
{
|
||||||
|
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We reached the end of all monitors.
|
||||||
|
// Try again, cycling on all monitors.
|
||||||
|
// First, add zones from the origin monitor to zoneRects
|
||||||
|
// Sanity check: the current monitor is valid
|
||||||
|
if (currentMonitorRect.top <= currentMonitorRect.bottom)
|
||||||
|
{
|
||||||
|
const auto& currentWorkArea = activeWorkAreas.at(current);
|
||||||
|
if (currentWorkArea)
|
||||||
|
{
|
||||||
|
const auto& layout = currentWorkArea->GetLayout();
|
||||||
|
if (layout)
|
||||||
|
{
|
||||||
|
const auto& zones = layout->Zones();
|
||||||
|
for (const auto& [zoneId, zone] : zones)
|
||||||
|
{
|
||||||
|
RECT zoneRect = zone.GetZoneRect();
|
||||||
|
|
||||||
|
zoneRect.left += currentMonitorRect.left;
|
||||||
|
zoneRect.right += currentMonitorRect.left;
|
||||||
|
zoneRect.top += currentMonitorRect.top;
|
||||||
|
zoneRect.bottom += currentMonitorRect.top;
|
||||||
|
|
||||||
|
zoneRects.emplace_back(zoneRect);
|
||||||
|
zoneRectsInfo.emplace_back(zoneId, currentWorkArea.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT combinedRect = FancyZonesUtils::GetMonitorsCombinedRect<&MONITORINFOEX::rcWork>(monitors);
|
||||||
|
windowRect = FancyZonesUtils::PrepareRectForCycling(windowRect, combinedRect, vkCode);
|
||||||
|
chosenIdx = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
||||||
|
if (chosenIdx < zoneRects.size())
|
||||||
|
{
|
||||||
|
// Moving to another monitor succeeded
|
||||||
|
const auto& [trueZoneIdx, workArea] = zoneRectsInfo[chosenIdx];
|
||||||
|
|
||||||
|
bool snapped = false;
|
||||||
|
if (workArea)
|
||||||
|
{
|
||||||
|
snapped = workArea->Snap(window, { trueZoneIdx });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapped)
|
||||||
|
{
|
||||||
|
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapped;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Giving up
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowKeyboardSnap::MoveByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, WorkArea* const workArea)
|
||||||
|
{
|
||||||
|
if (!workArea)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& layout = workArea->GetLayout();
|
||||||
|
const auto& zones = layout->Zones();
|
||||||
|
const auto& layoutWindows = workArea->GetLayoutWindows();
|
||||||
|
if (!layout || zones.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto zoneIndexes = layoutWindows.GetZoneIndexSetFromWindow(window);
|
||||||
|
const auto numZones = zones.size();
|
||||||
|
bool snapped = false;
|
||||||
|
|
||||||
|
// The window was not assigned to any zone here
|
||||||
|
if (zoneIndexes.size() == 0)
|
||||||
|
{
|
||||||
|
const ZoneIndex zone = vkCode == VK_LEFT ? numZones - 1 : 0;
|
||||||
|
snapped = workArea->Snap(window, { zone });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
if (!cycle)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZoneIndex zone = vkCode == VK_LEFT ? numZones - 1 : 0;
|
||||||
|
snapped = workArea->Snap(window, { zone });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We didn't reach the edge
|
||||||
|
if (vkCode == VK_LEFT)
|
||||||
|
{
|
||||||
|
snapped = workArea->Snap(window, { oldId - 1 });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snapped = workArea->Snap(window, { oldId + 1 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapped)
|
||||||
|
{
|
||||||
|
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowKeyboardSnap::MoveByDirectionAndPosition(HWND window, RECT windowRect, DWORD vkCode, bool cycle, WorkArea* const workArea)
|
||||||
|
{
|
||||||
|
if (!workArea)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& layout = workArea->GetLayout();
|
||||||
|
const auto& zones = layout->Zones();
|
||||||
|
const auto& layoutWindows = workArea->GetLayoutWindows();
|
||||||
|
if (!layout || zones.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bool> usedZoneIndices(zones.size(), false);
|
||||||
|
auto windowZones = layoutWindows.GetZoneIndexSetFromWindow(window);
|
||||||
|
|
||||||
|
for (const ZoneIndex id : windowZones)
|
||||||
|
{
|
||||||
|
usedZoneIndices[id] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RECT> zoneRects;
|
||||||
|
ZoneIndexSet freeZoneIndices;
|
||||||
|
|
||||||
|
for (const auto& [zoneId, zone] : zones)
|
||||||
|
{
|
||||||
|
if (!usedZoneIndices[zoneId])
|
||||||
|
{
|
||||||
|
zoneRects.emplace_back(zones.at(zoneId).GetZoneRect());
|
||||||
|
freeZoneIndices.emplace_back(zoneId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to coordinates relative to windowZone
|
||||||
|
const auto& workAreaRect = workArea->GetWorkAreaRect();
|
||||||
|
windowRect.top -= workAreaRect.top();
|
||||||
|
windowRect.bottom -= workAreaRect.top();
|
||||||
|
windowRect.left -= workAreaRect.left();
|
||||||
|
windowRect.right -= workAreaRect.left();
|
||||||
|
|
||||||
|
ZoneIndex result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
||||||
|
if (static_cast<size_t>(result) < zoneRects.size())
|
||||||
|
{
|
||||||
|
bool success = workArea->Snap(window, { freeZoneIndices[result] });
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Trace::FancyZones::KeyboardSnapWindowToZone(layout.get(), layoutWindows);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
else if (cycle)
|
||||||
|
{
|
||||||
|
// Try again from the position off the screen in the opposite direction to vkCode
|
||||||
|
// Consider all zones as available
|
||||||
|
zoneRects.resize(zones.size());
|
||||||
|
std::transform(zones.begin(), zones.end(), zoneRects.begin(), [](auto zone) { return zone.second.GetZoneRect(); });
|
||||||
|
windowRect = FancyZonesUtils::PrepareRectForCycling(windowRect, RECT(workAreaRect.left(), workAreaRect.top(), workAreaRect.right(), workAreaRect.bottom()), vkCode);
|
||||||
|
result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
||||||
|
|
||||||
|
if (static_cast<size_t>(result) < zoneRects.size())
|
||||||
|
{
|
||||||
|
bool success = workArea->Snap(window, { result });
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Trace::FancyZones::KeyboardSnapWindowToZone(layout.get(), layoutWindows);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowKeyboardSnap::Extend(HWND window, RECT windowRect, DWORD vkCode, WorkArea* const workArea)
|
||||||
|
{
|
||||||
|
if (!workArea)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& layout = workArea->GetLayout();
|
||||||
|
const auto& layoutWindows = workArea->GetLayoutWindows();
|
||||||
|
if (!layout || layout->Zones().empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& zones = layout->Zones();
|
||||||
|
auto appliedZones = layoutWindows.GetZoneIndexSetFromWindow(window);
|
||||||
|
|
||||||
|
std::vector<bool> usedZoneIndices(zones.size(), false);
|
||||||
|
std::vector<RECT> zoneRects;
|
||||||
|
ZoneIndexSet freeZoneIndices;
|
||||||
|
|
||||||
|
// If selectManyZones = true for the second time, use the last zone into which we moved
|
||||||
|
// instead of the window rect and enable moving to all zones except the old one
|
||||||
|
if (m_extendData.IsExtended(window))
|
||||||
|
{
|
||||||
|
usedZoneIndices[m_extendData.windowFinalIndex] = true;
|
||||||
|
windowRect = zones.at(m_extendData.windowFinalIndex).GetZoneRect();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const ZoneIndex idx : appliedZones)
|
||||||
|
{
|
||||||
|
usedZoneIndices[idx] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to coordinates relative to windowZone
|
||||||
|
const auto& workAreaRect = workArea->GetWorkAreaRect();
|
||||||
|
windowRect.top -= workAreaRect.top();
|
||||||
|
windowRect.bottom -= workAreaRect.top();
|
||||||
|
windowRect.left -= workAreaRect.left();
|
||||||
|
windowRect.right -= workAreaRect.left();
|
||||||
|
|
||||||
|
m_extendData.Set(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < zones.size(); i++)
|
||||||
|
{
|
||||||
|
if (!usedZoneIndices[i])
|
||||||
|
{
|
||||||
|
zoneRects.emplace_back(zones.at(i).GetZoneRect());
|
||||||
|
freeZoneIndices.emplace_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
||||||
|
if (result >= zoneRects.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneIndex targetZone = freeZoneIndices[result];
|
||||||
|
ZoneIndexSet resultIndexSet;
|
||||||
|
|
||||||
|
// First time with selectManyZones = true for this window?
|
||||||
|
if (m_extendData.windowFinalIndex == -1)
|
||||||
|
{
|
||||||
|
// Already zoned?
|
||||||
|
if (appliedZones.size())
|
||||||
|
{
|
||||||
|
m_extendData.windowInitialIndexSet = appliedZones;
|
||||||
|
m_extendData.windowFinalIndex = targetZone;
|
||||||
|
resultIndexSet = layout->GetCombinedZoneRange(appliedZones, { targetZone });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_extendData.windowInitialIndexSet = { targetZone };
|
||||||
|
m_extendData.windowFinalIndex = targetZone;
|
||||||
|
resultIndexSet = { targetZone };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto deletethis = m_extendData.windowInitialIndexSet;
|
||||||
|
m_extendData.windowFinalIndex = targetZone;
|
||||||
|
resultIndexSet = layout->GetCombinedZoneRange(m_extendData.windowInitialIndexSet, { targetZone });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = workArea->Snap(window, resultIndexSet);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
Trace::FancyZones::KeyboardSnapWindowToZone(workArea->GetLayout().get(), workArea->GetLayoutWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
56
src/modules/fancyzones/FancyZonesLib/WindowKeyboardSnap.h
Normal file
56
src/modules/fancyzones/FancyZonesLib/WindowKeyboardSnap.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <FancyZonesLib/Zone.h>
|
||||||
|
|
||||||
|
class WorkArea;
|
||||||
|
|
||||||
|
class WindowKeyboardSnap
|
||||||
|
{
|
||||||
|
struct ExtendWindowModeData
|
||||||
|
{
|
||||||
|
HWND window{ nullptr };
|
||||||
|
ZoneIndexSet windowInitialIndexSet{};
|
||||||
|
ZoneIndex windowFinalIndex{ -1 };
|
||||||
|
|
||||||
|
bool IsExtended(HWND wnd) const
|
||||||
|
{
|
||||||
|
return window == wnd && windowFinalIndex != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(HWND w)
|
||||||
|
{
|
||||||
|
window = w;
|
||||||
|
windowFinalIndex = -1;
|
||||||
|
windowInitialIndexSet.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
window = nullptr;
|
||||||
|
windowFinalIndex = -1;
|
||||||
|
windowInitialIndexSet.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
WindowKeyboardSnap() = default;
|
||||||
|
~WindowKeyboardSnap() = default;
|
||||||
|
|
||||||
|
bool Snap(HWND window, HMONITOR activeMonitor, DWORD vkCode,
|
||||||
|
const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas,
|
||||||
|
const std::vector<HMONITOR>& monitors);
|
||||||
|
bool Snap(HWND window, RECT windowRect, HMONITOR activeMonitor, DWORD vkCode,
|
||||||
|
const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas,
|
||||||
|
const std::vector<std::pair<HMONITOR, RECT>>& monitors);
|
||||||
|
bool Extend(HWND window, RECT windowRect, HMONITOR monitor, DWORD vkCode, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool SnapHotkeyBasedOnZoneNumber(HWND window, DWORD vkCode, HMONITOR monitor, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas, const std::vector<HMONITOR>& monitors);
|
||||||
|
bool SnapBasedOnPositionOnAnotherMonitor(HWND window, RECT windowRect, DWORD vkCode, HMONITOR monitor, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas, const std::vector<std::pair<HMONITOR, RECT>>& monitors);
|
||||||
|
|
||||||
|
bool MoveByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle, WorkArea* const workArea);
|
||||||
|
bool MoveByDirectionAndPosition(HWND window, RECT windowRect, DWORD vkCode, bool cycle, WorkArea* const workArea);
|
||||||
|
bool Extend(HWND window, RECT windowRect, DWORD vkCode, WorkArea* const workArea);
|
||||||
|
|
||||||
|
ExtendWindowModeData m_extendData{}; // Needed for ExtendWindowByDirectionAndPosition
|
||||||
|
};
|
||||||
244
src/modules/fancyzones/FancyZonesLib/WindowMouseSnap.cpp
Normal file
244
src/modules/fancyzones/FancyZonesLib/WindowMouseSnap.cpp
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "WindowMouseSnap.h"
|
||||||
|
|
||||||
|
#include <FancyZonesLib/FancyZonesData/AppZoneHistory.h>
|
||||||
|
#include <FancyZonesLib/FancyZonesWindowProcessing.h>
|
||||||
|
#include <FancyZonesLib/FancyZonesWindowProperties.h>
|
||||||
|
#include <FancyZonesLib/NotificationUtil.h>
|
||||||
|
#include <FancyZonesLib/Settings.h>
|
||||||
|
#include <FancyZonesLib/WindowUtils.h>
|
||||||
|
#include <FancyZonesLib/WorkArea.h>
|
||||||
|
|
||||||
|
#include <FancyZonesLib/trace.h>
|
||||||
|
|
||||||
|
#include <common/utils/elevation.h>
|
||||||
|
|
||||||
|
WindowMouseSnap::WindowMouseSnap(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);
|
||||||
|
m_windowProperties.isStandardWindow = FancyZonesWindowUtils::IsStandardWindow(m_window) &&
|
||||||
|
(!FancyZonesWindowUtils::IsPopupWindow(m_window) || FancyZonesSettings::settings().allowSnapPopupWindows);
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowMouseSnap::~WindowMouseSnap()
|
||||||
|
{
|
||||||
|
ResetWindowTransparency();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<WindowMouseSnap> WindowMouseSnap::Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas)
|
||||||
|
{
|
||||||
|
if (!FancyZonesWindowProcessing::IsProcessable(window) ||
|
||||||
|
!FancyZonesWindowUtils::IsCandidateForZoning(window) ||
|
||||||
|
FancyZonesWindowUtils::IsCursorTypeIndicatingSizeEvent())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_process_elevated() && FancyZonesWindowUtils::IsProcessOfWindowElevated(window))
|
||||||
|
{
|
||||||
|
// Notifies user if unable to drag elevated window
|
||||||
|
FancyZonesNotifications::WarnIfElevationIsRequired();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::unique_ptr<WindowMouseSnap>(new WindowMouseSnap(window, activeWorkAreas));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowMouseSnap::MoveSizeStart(HMONITOR monitor, bool isSnapping)
|
||||||
|
{
|
||||||
|
auto iter = m_activeWorkAreas.find(monitor);
|
||||||
|
if (iter == end(m_activeWorkAreas))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_currentWorkArea = iter->second.get();
|
||||||
|
|
||||||
|
SwitchSnappingMode(isSnapping);
|
||||||
|
|
||||||
|
if (m_currentWorkArea)
|
||||||
|
{
|
||||||
|
m_currentWorkArea->Unsnap(m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMouseSnap::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, bool isSnapping, bool isSelectManyZonesState)
|
||||||
|
{
|
||||||
|
auto iter = m_activeWorkAreas.find(monitor);
|
||||||
|
if (isSnapping && iter != m_activeWorkAreas.end())
|
||||||
|
{
|
||||||
|
// The drag has moved to a different monitor.
|
||||||
|
// Change work area
|
||||||
|
if (iter->second.get() != m_currentWorkArea)
|
||||||
|
{
|
||||||
|
m_highlightedZones.Reset();
|
||||||
|
|
||||||
|
if (m_currentWorkArea)
|
||||||
|
{
|
||||||
|
if (!FancyZonesSettings::settings().showZonesOnAllMonitors)
|
||||||
|
{
|
||||||
|
m_currentWorkArea->HideZones();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_currentWorkArea->ShowZones({}, m_window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_currentWorkArea = iter->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_currentWorkArea)
|
||||||
|
{
|
||||||
|
POINT ptClient = ptScreen;
|
||||||
|
MapWindowPoints(nullptr, m_currentWorkArea->GetWorkAreaWindow(), &ptClient, 1);
|
||||||
|
const bool redraw = m_highlightedZones.Update(m_currentWorkArea->GetLayout().get(), ptClient, isSelectManyZonesState);
|
||||||
|
if (redraw)
|
||||||
|
{
|
||||||
|
m_currentWorkArea->ShowZones(m_highlightedZones.Zones(), m_window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchSnappingMode(isSnapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMouseSnap::MoveSizeEnd()
|
||||||
|
{
|
||||||
|
if (m_snappingMode)
|
||||||
|
{
|
||||||
|
const bool hasNoVisibleOwner = !FancyZonesWindowUtils::HasVisibleOwner(m_window);
|
||||||
|
const bool isStandardWindow = FancyZonesWindowUtils::IsStandardWindow(m_window);
|
||||||
|
|
||||||
|
if ((isStandardWindow == false && hasNoVisibleOwner == true &&
|
||||||
|
m_windowProperties.isStandardWindow == true && m_windowProperties.hasNoVisibleOwner == true) ||
|
||||||
|
FancyZonesWindowUtils::IsWindowMaximized(m_window))
|
||||||
|
{
|
||||||
|
// Abort the zoning, this is a Chromium based tab that is merged back with an existing window
|
||||||
|
// or if the window is maximized by Windows when the cursor hits the screen top border
|
||||||
|
}
|
||||||
|
else if (m_currentWorkArea)
|
||||||
|
{
|
||||||
|
m_currentWorkArea->Snap(m_window, m_highlightedZones.Zones());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FancyZonesWindowUtils::ResetRoundCornersPreference(m_window);
|
||||||
|
if (FancyZonesSettings::settings().restoreSize)
|
||||||
|
{
|
||||||
|
if (FancyZonesWindowUtils::IsCursorTypeIndicatingSizeEvent())
|
||||||
|
{
|
||||||
|
::RemoveProp(m_window, ZonedWindowProperties::PropertyRestoreSizeID);
|
||||||
|
}
|
||||||
|
else if (!FancyZonesWindowUtils::IsWindowMaximized(m_window))
|
||||||
|
{
|
||||||
|
FancyZonesWindowUtils::RestoreWindowSize(m_window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchSnappingMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMouseSnap::SwitchSnappingMode(bool isSnapping)
|
||||||
|
{
|
||||||
|
if (!m_snappingMode && isSnapping) // turn on
|
||||||
|
{
|
||||||
|
m_highlightedZones.Reset();
|
||||||
|
SetWindowTransparency();
|
||||||
|
|
||||||
|
if (FancyZonesSettings::settings().showZonesOnAllMonitors)
|
||||||
|
{
|
||||||
|
for (const auto& [_, workArea] : m_activeWorkAreas)
|
||||||
|
{
|
||||||
|
if (workArea)
|
||||||
|
{
|
||||||
|
workArea->ShowZones({}, m_window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_currentWorkArea)
|
||||||
|
{
|
||||||
|
m_currentWorkArea->ShowZones({}, m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_currentWorkArea)
|
||||||
|
{
|
||||||
|
m_currentWorkArea->Unsnap(m_window);
|
||||||
|
Trace::WorkArea::MoveOrResizeStarted(m_currentWorkArea->GetLayout().get(), m_currentWorkArea->GetLayoutWindows());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_snappingMode && !isSnapping) // turn off
|
||||||
|
{
|
||||||
|
ResetWindowTransparency();
|
||||||
|
m_highlightedZones.Reset();
|
||||||
|
|
||||||
|
// Hide all layouts (regardless of settings)
|
||||||
|
for (auto& [_, workArea] : m_activeWorkAreas)
|
||||||
|
{
|
||||||
|
if (workArea)
|
||||||
|
{
|
||||||
|
workArea->HideZones();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_currentWorkArea)
|
||||||
|
{
|
||||||
|
Trace::WorkArea::MoveOrResizeEnd(m_currentWorkArea->GetLayout().get(), m_currentWorkArea->GetLayoutWindows());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_snappingMode = isSnapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMouseSnap::SetWindowTransparency()
|
||||||
|
{
|
||||||
|
if (FancyZonesSettings::settings().makeDraggedWindowTransparent)
|
||||||
|
{
|
||||||
|
m_windowProperties.exstyle = GetWindowLong(m_window, GWL_EXSTYLE);
|
||||||
|
|
||||||
|
SetWindowLong(m_window, GWL_EXSTYLE, m_windowProperties.exstyle | WS_EX_LAYERED);
|
||||||
|
|
||||||
|
if (!GetLayeredWindowAttributes(m_window, &m_windowProperties.crKey, &m_windowProperties.alpha, &m_windowProperties.dwFlags))
|
||||||
|
{
|
||||||
|
Logger::error(L"Window transparency: GetLayeredWindowAttributes failed, {}", get_last_error_or_default(GetLastError()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetLayeredWindowAttributes(m_window, 0, (255 * 50) / 100, LWA_ALPHA))
|
||||||
|
{
|
||||||
|
Logger::error(L"Window transparency: SetLayeredWindowAttributes failed, {}", get_last_error_or_default(GetLastError()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_windowProperties.transparencySet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMouseSnap::ResetWindowTransparency()
|
||||||
|
{
|
||||||
|
if (FancyZonesSettings::settings().makeDraggedWindowTransparent && m_windowProperties.transparencySet)
|
||||||
|
{
|
||||||
|
bool reset = true;
|
||||||
|
if (!SetLayeredWindowAttributes(m_window, m_windowProperties.crKey, m_windowProperties.alpha, m_windowProperties.dwFlags))
|
||||||
|
{
|
||||||
|
Logger::error(L"Window transparency: SetLayeredWindowAttributes failed, {}", get_last_error_or_default(GetLastError()));
|
||||||
|
reset = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SetWindowLong(m_window, GWL_EXSTYLE, m_windowProperties.exstyle) == 0)
|
||||||
|
{
|
||||||
|
Logger::error(L"Window transparency: SetWindowLong failed, {}", get_last_error_or_default(GetLastError()));
|
||||||
|
reset = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_windowProperties.transparencySet = !reset;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
class WorkArea;
|
class WorkArea;
|
||||||
|
|
||||||
class WindowDrag
|
class WindowMouseSnap
|
||||||
{
|
{
|
||||||
WindowDrag(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);
|
WindowMouseSnap(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<WindowDrag> Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);
|
static std::unique_ptr<WindowMouseSnap> Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas);
|
||||||
~WindowDrag();
|
~WindowMouseSnap();
|
||||||
|
|
||||||
bool MoveSizeStart(HMONITOR monitor, bool isSnapping);
|
bool MoveSizeStart(HMONITOR monitor, bool isSnapping);
|
||||||
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, bool isSnapping, bool isSelectManyZonesState);
|
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, bool isSnapping, bool isSelectManyZonesState);
|
||||||
@@ -456,15 +456,19 @@ RECT FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(HWND window, RECT rect
|
|||||||
::GetWindowRect(window, &windowRect);
|
::GetWindowRect(window, &windowRect);
|
||||||
|
|
||||||
// Take care of borders
|
// Take care of borders
|
||||||
RECT frameRect{};
|
// Skip when windowOfRect is not initialized (in unit tests)
|
||||||
if (SUCCEEDED(DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect))))
|
if (windowOfRect)
|
||||||
{
|
{
|
||||||
LONG leftMargin = frameRect.left - windowRect.left;
|
RECT frameRect{};
|
||||||
LONG rightMargin = frameRect.right - windowRect.right;
|
if (SUCCEEDED(DwmGetWindowAttribute(window, DWMWA_EXTENDED_FRAME_BOUNDS, &frameRect, sizeof(frameRect))))
|
||||||
LONG bottomMargin = frameRect.bottom - windowRect.bottom;
|
{
|
||||||
newWindowRect.left -= leftMargin;
|
LONG leftMargin = frameRect.left - windowRect.left;
|
||||||
newWindowRect.right -= rightMargin;
|
LONG rightMargin = frameRect.right - windowRect.right;
|
||||||
newWindowRect.bottom -= bottomMargin;
|
LONG bottomMargin = frameRect.bottom - windowRect.bottom;
|
||||||
|
newWindowRect.left -= leftMargin;
|
||||||
|
newWindowRect.right -= rightMargin;
|
||||||
|
newWindowRect.bottom -= bottomMargin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take care of windows that cannot be resized
|
// Take care of windows that cannot be resized
|
||||||
@@ -475,7 +479,10 @@ RECT FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(HWND window, RECT rect
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert to screen coordinates
|
// Convert to screen coordinates
|
||||||
MapWindowRect(windowOfRect, nullptr, &newWindowRect);
|
if (windowOfRect)
|
||||||
|
{
|
||||||
|
MapWindowRect(windowOfRect, nullptr, &newWindowRect);
|
||||||
|
}
|
||||||
|
|
||||||
return newWindowRect;
|
return newWindowRect;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,16 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "WorkArea.h"
|
#include "WorkArea.h"
|
||||||
|
|
||||||
#include <common/logger/call_tracer.h>
|
|
||||||
#include <common/logger/logger.h>
|
#include <common/logger/logger.h>
|
||||||
#include <common/utils/winapi_error.h>
|
|
||||||
|
|
||||||
#include "FancyZonesData/AppliedLayouts.h"
|
#include "FancyZonesData/AppliedLayouts.h"
|
||||||
#include "FancyZonesData/AppZoneHistory.h"
|
#include "FancyZonesData/AppZoneHistory.h"
|
||||||
#include "FancyZonesDataTypes.h"
|
|
||||||
#include "SettingsObserver.h"
|
|
||||||
#include "ZonesOverlay.h"
|
#include "ZonesOverlay.h"
|
||||||
#include "trace.h"
|
|
||||||
#include "on_thread_executor.h"
|
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include <FancyZonesLib/FancyZonesWindowProperties.h>
|
#include <FancyZonesLib/FancyZonesWindowProperties.h>
|
||||||
#include <FancyZonesLib/VirtualDesktop.h>
|
#include <FancyZonesLib/VirtualDesktop.h>
|
||||||
#include <FancyZonesLib/WindowUtils.h>
|
#include <FancyZonesLib/WindowUtils.h>
|
||||||
|
|
||||||
#include <ShellScalingApi.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include <fileapi.h>
|
|
||||||
|
|
||||||
// disabling warning 4458 - declaration of 'identifier' hides class member
|
// disabling warning 4458 - declaration of 'identifier' hides class member
|
||||||
// to avoid warnings from GDI files - can't add winRT directory to external code
|
// to avoid warnings from GDI files - can't add winRT directory to external code
|
||||||
// in the Cpp.Build.props
|
// in the Cpp.Build.props
|
||||||
@@ -127,284 +117,41 @@ WorkArea::~WorkArea()
|
|||||||
windowPool.FreeZonesOverlayWindow(m_window);
|
windowPool.FreeZonesOverlayWindow(m_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorkArea::MoveWindowIntoZoneByIndex(HWND window, ZoneIndex index)
|
bool WorkArea::Snap(HWND window, const ZoneIndexSet& zones, bool updatePosition)
|
||||||
{
|
{
|
||||||
MoveWindowIntoZoneByIndexSet(window, { index });
|
if (!m_layout || zones.empty())
|
||||||
}
|
|
||||||
|
|
||||||
void WorkArea::MoveWindowIntoZoneByIndexSet(HWND window, const ZoneIndexSet& indexSet, bool updatePosition /* = true*/)
|
|
||||||
{
|
|
||||||
if (!m_layout || !m_layoutWindows || m_layout->Zones().empty() || indexSet.empty())
|
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FancyZonesWindowUtils::SaveWindowSizeAndOrigin(window);
|
m_layoutWindows.Assign(window, zones);
|
||||||
|
AppZoneHistory::instance().SetAppLastZones(window, m_uniqueId, m_layout->Id(), zones);
|
||||||
|
|
||||||
if (updatePosition)
|
if (updatePosition)
|
||||||
{
|
{
|
||||||
const auto rect = m_layout->GetCombinedZonesRect(indexSet);
|
const auto rect = m_layout->GetCombinedZonesRect(zones);
|
||||||
if (rect.bottom - rect.top > 0 && rect.right - rect.left > 0)
|
const auto adjustedRect = FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(window, rect, m_window);
|
||||||
{
|
FancyZonesWindowUtils::SaveWindowSizeAndOrigin(window);
|
||||||
const auto adjustedRect = FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(window, rect, m_window);
|
FancyZonesWindowUtils::SizeWindowToRect(window, adjustedRect);
|
||||||
FancyZonesWindowUtils::SizeWindowToRect(window, adjustedRect);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SnapWindow(window, indexSet);
|
return FancyZonesWindowProperties::StampZoneIndexProperty(window, zones);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorkArea::MoveWindowIntoZoneByDirectionAndIndex(HWND window, DWORD vkCode, bool cycle)
|
bool WorkArea::Unsnap(HWND window)
|
||||||
{
|
{
|
||||||
if (!m_layout || !m_layoutWindows || m_layout->Zones().empty())
|
if (!m_layout)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto zoneIndexes = m_layoutWindows->GetZoneIndexSetFromWindow(window);
|
m_layoutWindows.Dismiss(window);
|
||||||
const auto numZones = m_layout->Zones().size();
|
AppZoneHistory::instance().RemoveAppLastZone(window, m_uniqueId, m_layout->Id());
|
||||||
|
FancyZonesWindowProperties::RemoveZoneIndexProperty(window);
|
||||||
// The window was not assigned to any zone here
|
|
||||||
if (zoneIndexes.size() == 0)
|
|
||||||
{
|
|
||||||
MoveWindowIntoZoneByIndex(window, vkCode == VK_LEFT ? numZones - 1 : 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
if (!cycle)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveWindowIntoZoneByIndex(window, vkCode == VK_LEFT ? numZones - 1 : 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We didn't reach the edge
|
|
||||||
if (vkCode == VK_LEFT)
|
|
||||||
{
|
|
||||||
MoveWindowIntoZoneByIndex(window, oldId - 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MoveWindowIntoZoneByIndex(window, oldId + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorkArea::MoveWindowIntoZoneByDirectionAndPosition(HWND window, DWORD vkCode, bool cycle)
|
|
||||||
{
|
|
||||||
if (!m_layout || !m_layoutWindows || m_layout->Zones().empty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& zones = m_layout->Zones();
|
|
||||||
std::vector<bool> usedZoneIndices(zones.size(), false);
|
|
||||||
auto windowZones = m_layoutWindows->GetZoneIndexSetFromWindow(window);
|
|
||||||
|
|
||||||
for (const ZoneIndex id : windowZones)
|
|
||||||
{
|
|
||||||
usedZoneIndices[id] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<RECT> zoneRects;
|
|
||||||
ZoneIndexSet freeZoneIndices;
|
|
||||||
|
|
||||||
for (const auto& [zoneId, zone] : zones)
|
|
||||||
{
|
|
||||||
if (!usedZoneIndices[zoneId])
|
|
||||||
{
|
|
||||||
zoneRects.emplace_back(zones.at(zoneId).GetZoneRect());
|
|
||||||
freeZoneIndices.emplace_back(zoneId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT windowRect;
|
|
||||||
if (!GetWindowRect(window, &windowRect))
|
|
||||||
{
|
|
||||||
Logger::error(L"GetWindowRect failed, {}", get_last_error_or_default(GetLastError()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to coordinates relative to windowZone
|
|
||||||
windowRect.top -= m_workAreaRect.top();
|
|
||||||
windowRect.bottom -= m_workAreaRect.top();
|
|
||||||
windowRect.left -= m_workAreaRect.left();
|
|
||||||
windowRect.right -= m_workAreaRect.left();
|
|
||||||
|
|
||||||
auto result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
|
||||||
if (result < zoneRects.size())
|
|
||||||
{
|
|
||||||
MoveWindowIntoZoneByIndex(window, freeZoneIndices[result]);
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(m_layout.get(), m_layoutWindows.get());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (cycle)
|
|
||||||
{
|
|
||||||
// Try again from the position off the screen in the opposite direction to vkCode
|
|
||||||
// Consider all zones as available
|
|
||||||
zoneRects.resize(zones.size());
|
|
||||||
std::transform(zones.begin(), zones.end(), zoneRects.begin(), [](auto zone) { return zone.second.GetZoneRect(); });
|
|
||||||
windowRect = FancyZonesUtils::PrepareRectForCycling(windowRect, RECT(m_workAreaRect.left(), m_workAreaRect.top(), m_workAreaRect.right(), m_workAreaRect.bottom()), vkCode);
|
|
||||||
result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
|
||||||
|
|
||||||
if (result < zoneRects.size())
|
|
||||||
{
|
|
||||||
MoveWindowIntoZoneByIndex(window, result);
|
|
||||||
Trace::FancyZones::KeyboardSnapWindowToZone(m_layout.get(), m_layoutWindows.get());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WorkArea::ExtendWindowByDirectionAndPosition(HWND window, DWORD vkCode)
|
|
||||||
{
|
|
||||||
if (!m_layout || !m_layoutWindows || m_layout->Zones().empty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT windowRect;
|
|
||||||
if (!GetWindowRect(window, &windowRect))
|
|
||||||
{
|
|
||||||
Logger::error(L"GetWindowRect failed, {}", get_last_error_or_default(GetLastError()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& zones = m_layout->Zones();
|
|
||||||
auto appliedZones = m_layoutWindows->GetZoneIndexSetFromWindow(window);
|
|
||||||
const auto& extendModeData = m_layoutWindows->ExtendWindowData();
|
|
||||||
|
|
||||||
std::vector<bool> usedZoneIndices(zones.size(), false);
|
|
||||||
std::vector<RECT> zoneRects;
|
|
||||||
ZoneIndexSet freeZoneIndices;
|
|
||||||
|
|
||||||
// If selectManyZones = true for the second time, use the last zone into which we moved
|
|
||||||
// instead of the window rect and enable moving to all zones except the old one
|
|
||||||
auto finalIndexIt = extendModeData->windowFinalIndex.find(window);
|
|
||||||
if (finalIndexIt != extendModeData->windowFinalIndex.end())
|
|
||||||
{
|
|
||||||
usedZoneIndices[finalIndexIt->second] = true;
|
|
||||||
windowRect = zones.at(finalIndexIt->second).GetZoneRect();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (const ZoneIndex idx : appliedZones)
|
|
||||||
{
|
|
||||||
usedZoneIndices[idx] = true;
|
|
||||||
}
|
|
||||||
// Move to coordinates relative to windowZone
|
|
||||||
windowRect.top -= m_workAreaRect.top();
|
|
||||||
windowRect.bottom -= m_workAreaRect.top();
|
|
||||||
windowRect.left -= m_workAreaRect.left();
|
|
||||||
windowRect.right -= m_workAreaRect.left();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < zones.size(); i++)
|
|
||||||
{
|
|
||||||
if (!usedZoneIndices[i])
|
|
||||||
{
|
|
||||||
zoneRects.emplace_back(zones.at(i).GetZoneRect());
|
|
||||||
freeZoneIndices.emplace_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto result = FancyZonesUtils::ChooseNextZoneByPosition(vkCode, windowRect, zoneRects);
|
|
||||||
if (result < zoneRects.size())
|
|
||||||
{
|
|
||||||
ZoneIndex targetZone = freeZoneIndices[result];
|
|
||||||
ZoneIndexSet resultIndexSet;
|
|
||||||
|
|
||||||
// First time with selectManyZones = true for this window?
|
|
||||||
if (finalIndexIt == extendModeData->windowFinalIndex.end())
|
|
||||||
{
|
|
||||||
// Already zoned?
|
|
||||||
if (appliedZones.size())
|
|
||||||
{
|
|
||||||
extendModeData->windowInitialIndexSet[window] = appliedZones;
|
|
||||||
extendModeData->windowFinalIndex[window] = targetZone;
|
|
||||||
resultIndexSet = m_layout->GetCombinedZoneRange(appliedZones, { targetZone });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
extendModeData->windowInitialIndexSet[window] = { targetZone };
|
|
||||||
extendModeData->windowFinalIndex[window] = targetZone;
|
|
||||||
resultIndexSet = { targetZone };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto deletethis = extendModeData->windowInitialIndexSet[window];
|
|
||||||
extendModeData->windowFinalIndex[window] = targetZone;
|
|
||||||
resultIndexSet = m_layout->GetCombinedZoneRange(extendModeData->windowInitialIndexSet[window], { targetZone });
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto rect = m_layout->GetCombinedZonesRect(resultIndexSet);
|
|
||||||
const auto adjustedRect = FancyZonesWindowUtils::AdjustRectForSizeWindowToRect(window, rect, m_window);
|
|
||||||
FancyZonesWindowUtils::SizeWindowToRect(window, adjustedRect);
|
|
||||||
|
|
||||||
SnapWindow(window, resultIndexSet, true);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorkArea::SnapWindow(HWND window, const ZoneIndexSet& zones, bool extend)
|
|
||||||
{
|
|
||||||
if (!m_layoutWindows || !m_layout)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extend)
|
|
||||||
{
|
|
||||||
m_layoutWindows->Extend(window, zones);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorkArea::UnsnapWindow(HWND window)
|
|
||||||
{
|
|
||||||
if (!m_layoutWindows || !m_layout)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_layoutWindows->Dismiss(window);
|
|
||||||
|
|
||||||
auto guidStr = FancyZonesUtils::GuidToString(m_layout->Id());
|
|
||||||
if (guidStr.has_value())
|
|
||||||
{
|
|
||||||
AppZoneHistory::instance().RemoveAppLastZone(window, m_uniqueId, guidStr.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
FancyZonesWindowProperties::RemoveZoneIndexProperty(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GUID WorkArea::GetLayoutId() const noexcept
|
const GUID WorkArea::GetLayoutId() const noexcept
|
||||||
{
|
{
|
||||||
if (m_layout)
|
if (m_layout)
|
||||||
@@ -415,29 +162,7 @@ const GUID WorkArea::GetLayoutId() const noexcept
|
|||||||
return GUID{};
|
return GUID{};
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneIndexSet WorkArea::GetWindowZoneIndexes(HWND window) const
|
void WorkArea::ShowZones(const ZoneIndexSet& highlight, HWND draggedWindow/* = nullptr*/)
|
||||||
{
|
|
||||||
if (m_layout)
|
|
||||||
{
|
|
||||||
auto guidStr = FancyZonesUtils::GuidToString(m_layout->Id());
|
|
||||||
if (guidStr.has_value())
|
|
||||||
{
|
|
||||||
return AppZoneHistory::instance().GetAppLastZoneIndexSet(window, m_uniqueId, guidStr.value());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger::error(L"Failed to convert to string layout GUID on the requested work area");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger::error(L"No layout initialized on the requested work area");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorkArea::ShowZonesOverlay(const ZoneIndexSet& highlight, HWND draggedWindow/* = nullptr*/)
|
|
||||||
{
|
{
|
||||||
if (m_layout && m_zonesOverlay)
|
if (m_layout && m_zonesOverlay)
|
||||||
{
|
{
|
||||||
@@ -447,7 +172,7 @@ void WorkArea::ShowZonesOverlay(const ZoneIndexSet& highlight, HWND draggedWindo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorkArea::HideZonesOverlay()
|
void WorkArea::HideZones()
|
||||||
{
|
{
|
||||||
if (m_zonesOverlay)
|
if (m_zonesOverlay)
|
||||||
{
|
{
|
||||||
@@ -465,15 +190,10 @@ void WorkArea::FlashZones()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorkArea::UpdateActiveZoneSet()
|
void WorkArea::InitLayout()
|
||||||
{
|
{
|
||||||
const bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId);
|
InitLayout({});
|
||||||
if (!isLayoutAlreadyApplied)
|
|
||||||
{
|
|
||||||
AppliedLayouts::instance().ApplyDefaultLayout(m_uniqueId);
|
|
||||||
}
|
|
||||||
|
|
||||||
CalculateZoneSet();
|
|
||||||
if (m_window && m_layout)
|
if (m_window && m_layout)
|
||||||
{
|
{
|
||||||
m_zonesOverlay->DrawActiveZoneSet(m_layout->Zones(), {}, Colors::GetZoneColors(), FancyZonesSettings::settings().showZoneNumber);
|
m_zonesOverlay->DrawActiveZoneSet(m_layout->Zones(), {}, Colors::GetZoneColors(), FancyZonesSettings::settings().showZoneNumber);
|
||||||
@@ -482,24 +202,16 @@ void WorkArea::UpdateActiveZoneSet()
|
|||||||
|
|
||||||
void WorkArea::UpdateWindowPositions()
|
void WorkArea::UpdateWindowPositions()
|
||||||
{
|
{
|
||||||
if (!m_layoutWindows)
|
const auto& snappedWindows = m_layoutWindows.SnappedWindows();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& snappedWindows = m_layoutWindows->SnappedWindows();
|
|
||||||
for (const auto& [window, zones] : snappedWindows)
|
for (const auto& [window, zones] : snappedWindows)
|
||||||
{
|
{
|
||||||
MoveWindowIntoZoneByIndexSet(window, zones, true);
|
Snap(window, zones, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorkArea::CycleWindows(HWND window, bool reverse)
|
void WorkArea::CycleWindows(HWND window, bool reverse)
|
||||||
{
|
{
|
||||||
if (m_layoutWindows)
|
m_layoutWindows.CycleWindows(window, reverse);
|
||||||
{
|
|
||||||
m_layoutWindows->CycleWindows(window, reverse);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma region private
|
#pragma region private
|
||||||
@@ -537,6 +249,46 @@ void WorkArea::InitLayout(const FancyZonesDataTypes::WorkAreaId& parentUniqueId)
|
|||||||
CalculateZoneSet();
|
CalculateZoneSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorkArea::InitSnappedWindows()
|
||||||
|
{
|
||||||
|
static bool updatePositionOnceOnStartFlag = true;
|
||||||
|
Logger::info(L"Init work area {} windows, update positions = {}", m_uniqueId.toString(), updatePositionOnceOnStartFlag);
|
||||||
|
|
||||||
|
for (const auto& window : VirtualDesktop::instance().GetWindowsFromCurrentDesktop())
|
||||||
|
{
|
||||||
|
auto indexes = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
|
||||||
|
if (indexes.size() == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_uniqueId.monitorId.monitor) // one work area across monitors
|
||||||
|
{
|
||||||
|
Snap(window, indexes, updatePositionOnceOnStartFlag);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
|
||||||
|
if (monitor && m_uniqueId.monitorId.monitor == monitor)
|
||||||
|
{
|
||||||
|
// prioritize snapping on the current monitor if the window was snapped to several work areas
|
||||||
|
Snap(window, indexes, updatePositionOnceOnStartFlag);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if the window is not snapped on the current monitor, then check the others
|
||||||
|
auto savedIndexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, m_uniqueId, GetLayoutId());
|
||||||
|
if (savedIndexes == indexes)
|
||||||
|
{
|
||||||
|
Snap(window, indexes, updatePositionOnceOnStartFlag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePositionOnceOnStartFlag = false;
|
||||||
|
}
|
||||||
|
|
||||||
void WorkArea::CalculateZoneSet()
|
void WorkArea::CalculateZoneSet()
|
||||||
{
|
{
|
||||||
const auto appliedLayout = AppliedLayouts::instance().GetDeviceLayout(m_uniqueId);
|
const auto appliedLayout = AppliedLayouts::instance().GetDeviceLayout(m_uniqueId);
|
||||||
@@ -548,11 +300,6 @@ void WorkArea::CalculateZoneSet()
|
|||||||
|
|
||||||
m_layout = std::make_unique<Layout>(appliedLayout.value());
|
m_layout = std::make_unique<Layout>(appliedLayout.value());
|
||||||
m_layout->Init(m_workAreaRect, m_uniqueId.monitorId.monitor);
|
m_layout->Init(m_workAreaRect, m_uniqueId.monitorId.monitor);
|
||||||
|
|
||||||
if (!m_layoutWindows)
|
|
||||||
{
|
|
||||||
m_layoutWindows = std::make_unique<LayoutAssignedWindows>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT WorkArea::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
LRESULT WorkArea::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <FancyZonesLib/FancyZonesDataTypes.h>
|
|
||||||
#include <FancyZonesLib/Layout.h>
|
#include <FancyZonesLib/Layout.h>
|
||||||
#include <FancyZonesLib/LayoutAssignedWindows.h>
|
#include <FancyZonesLib/LayoutAssignedWindows.h>
|
||||||
|
|
||||||
@@ -39,26 +38,20 @@ public:
|
|||||||
|
|
||||||
FancyZonesDataTypes::WorkAreaId UniqueId() const noexcept { return { m_uniqueId }; }
|
FancyZonesDataTypes::WorkAreaId UniqueId() const noexcept { return { m_uniqueId }; }
|
||||||
const std::unique_ptr<Layout>& GetLayout() const noexcept { return m_layout; }
|
const std::unique_ptr<Layout>& GetLayout() const noexcept { return m_layout; }
|
||||||
const std::unique_ptr<LayoutAssignedWindows>& GetLayoutWindows() const noexcept { return m_layoutWindows; }
|
const LayoutAssignedWindows& GetLayoutWindows() const noexcept { return m_layoutWindows; }
|
||||||
const HWND GetWorkAreaWindow() const noexcept { return m_window; }
|
const HWND GetWorkAreaWindow() const noexcept { return m_window; }
|
||||||
const GUID GetLayoutId() const noexcept;
|
const GUID GetLayoutId() const noexcept;
|
||||||
|
const FancyZonesUtils::Rect& GetWorkAreaRect() const noexcept { return m_workAreaRect; }
|
||||||
|
|
||||||
ZoneIndexSet GetWindowZoneIndexes(HWND window) const;
|
void InitLayout();
|
||||||
|
void InitSnappedWindows();
|
||||||
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 SnapWindow(HWND window, const ZoneIndexSet& zones, bool extend = false);
|
|
||||||
void UnsnapWindow(HWND window);
|
|
||||||
|
|
||||||
void UpdateActiveZoneSet();
|
|
||||||
void UpdateWindowPositions();
|
void UpdateWindowPositions();
|
||||||
|
|
||||||
void ShowZonesOverlay(const ZoneIndexSet& highlight, HWND draggedWindow = nullptr);
|
bool Snap(HWND window, const ZoneIndexSet& zones, bool updatePosition = true);
|
||||||
void HideZonesOverlay();
|
bool Unsnap(HWND window);
|
||||||
|
|
||||||
|
void ShowZones(const ZoneIndexSet& highlight, HWND draggedWindow = nullptr);
|
||||||
|
void HideZones();
|
||||||
void FlashZones();
|
void FlashZones();
|
||||||
|
|
||||||
void CycleWindows(HWND window, bool reverse);
|
void CycleWindows(HWND window, bool reverse);
|
||||||
@@ -79,6 +72,6 @@ private:
|
|||||||
const FancyZonesDataTypes::WorkAreaId m_uniqueId;
|
const FancyZonesDataTypes::WorkAreaId m_uniqueId;
|
||||||
HWND m_window{}; // Hidden tool window used to represent current monitor desktop work area.
|
HWND m_window{}; // Hidden tool window used to represent current monitor desktop work area.
|
||||||
std::unique_ptr<Layout> m_layout;
|
std::unique_ptr<Layout> m_layout;
|
||||||
std::unique_ptr<LayoutAssignedWindows> m_layoutWindows;
|
LayoutAssignedWindows m_layoutWindows{};
|
||||||
std::unique_ptr<ZonesOverlay> m_zonesOverlay;
|
std::unique_ptr<ZonesOverlay> m_zonesOverlay;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -90,17 +90,17 @@ struct ZoneSetInfo
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ZoneSetInfo GetZoneSetInfo(_In_opt_ Layout* layout, _In_opt_ LayoutAssignedWindows* layoutWindows) noexcept
|
ZoneSetInfo GetZoneSetInfo(_In_opt_ Layout* layout, const LayoutAssignedWindows& layoutWindows) noexcept
|
||||||
{
|
{
|
||||||
ZoneSetInfo info;
|
ZoneSetInfo info;
|
||||||
if (layout && layoutWindows)
|
if (layout)
|
||||||
{
|
{
|
||||||
auto zones = layout->Zones();
|
auto zones = layout->Zones();
|
||||||
info.NumberOfZones = zones.size();
|
info.NumberOfZones = zones.size();
|
||||||
info.NumberOfWindows = 0;
|
info.NumberOfWindows = 0;
|
||||||
for (int i = 0; i < static_cast<int>(zones.size()); i++)
|
for (int i = 0; i < static_cast<int>(zones.size()); i++)
|
||||||
{
|
{
|
||||||
if (!layoutWindows->IsZoneEmpty(i))
|
if (!layoutWindows.IsZoneEmpty(i))
|
||||||
{
|
{
|
||||||
info.NumberOfWindows++;
|
info.NumberOfWindows++;
|
||||||
}
|
}
|
||||||
@@ -258,7 +258,7 @@ void Trace::FancyZones::QuickLayoutSwitched(bool shortcutUsed) noexcept
|
|||||||
TraceLoggingBoolean(shortcutUsed, QuickLayoutSwitchedWithShortcutUsed));
|
TraceLoggingBoolean(shortcutUsed, QuickLayoutSwitchedWithShortcutUsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::FancyZones::SnapNewWindowIntoZone(Layout* activeLayout, LayoutAssignedWindows* layoutWindows) noexcept
|
void Trace::FancyZones::SnapNewWindowIntoZone(Layout* activeLayout, const LayoutAssignedWindows& layoutWindows) noexcept
|
||||||
{
|
{
|
||||||
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
||||||
TraceLoggingWrite(
|
TraceLoggingWrite(
|
||||||
@@ -271,7 +271,7 @@ void Trace::FancyZones::SnapNewWindowIntoZone(Layout* activeLayout, LayoutAssign
|
|||||||
TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey));
|
TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::FancyZones::KeyboardSnapWindowToZone(Layout* activeLayout, LayoutAssignedWindows* layoutWindows) noexcept
|
void Trace::FancyZones::KeyboardSnapWindowToZone(Layout* activeLayout, const LayoutAssignedWindows& layoutWindows) noexcept
|
||||||
{
|
{
|
||||||
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
||||||
TraceLoggingWrite(
|
TraceLoggingWrite(
|
||||||
@@ -356,7 +356,7 @@ void Trace::WorkArea::KeyUp(WPARAM wParam) noexcept
|
|||||||
TraceLoggingValue(wParam, KeyboardValueKey));
|
TraceLoggingValue(wParam, KeyboardValueKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::WorkArea::MoveOrResizeStarted(_In_opt_ Layout* activeLayout, _In_opt_ LayoutAssignedWindows* layoutWindows) noexcept
|
void Trace::WorkArea::MoveOrResizeStarted(_In_opt_ Layout* activeLayout, const LayoutAssignedWindows& layoutWindows) noexcept
|
||||||
{
|
{
|
||||||
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
||||||
TraceLoggingWrite(
|
TraceLoggingWrite(
|
||||||
@@ -369,7 +369,7 @@ void Trace::WorkArea::MoveOrResizeStarted(_In_opt_ Layout* activeLayout, _In_opt
|
|||||||
TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey));
|
TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::WorkArea::MoveOrResizeEnd(_In_opt_ Layout* activeLayout, _In_opt_ LayoutAssignedWindows* layoutWindows) noexcept
|
void Trace::WorkArea::MoveOrResizeEnd(_In_opt_ Layout* activeLayout, const LayoutAssignedWindows& layoutWindows) noexcept
|
||||||
{
|
{
|
||||||
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
||||||
TraceLoggingWrite(
|
TraceLoggingWrite(
|
||||||
@@ -382,7 +382,7 @@ void Trace::WorkArea::MoveOrResizeEnd(_In_opt_ Layout* activeLayout, _In_opt_ La
|
|||||||
TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey));
|
TraceLoggingValue(zoneInfo.NumberOfWindows, NumberOfWindowsKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Trace::WorkArea::CycleActiveZoneSet(_In_opt_ Layout* activeLayout, _In_opt_ LayoutAssignedWindows* layoutWindows, InputMode mode) noexcept
|
void Trace::WorkArea::CycleActiveZoneSet(_In_opt_ Layout* activeLayout, const LayoutAssignedWindows& layoutWindows, InputMode mode) noexcept
|
||||||
{
|
{
|
||||||
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
auto const zoneInfo = GetZoneSetInfo(activeLayout, layoutWindows);
|
||||||
TraceLoggingWrite(
|
TraceLoggingWrite(
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ public:
|
|||||||
static void EditorLaunched(int value) noexcept;
|
static void EditorLaunched(int value) noexcept;
|
||||||
static void Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept;
|
static void Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept;
|
||||||
static void QuickLayoutSwitched(bool shortcutUsed) noexcept;
|
static void QuickLayoutSwitched(bool shortcutUsed) noexcept;
|
||||||
static void SnapNewWindowIntoZone(Layout* activeLayout, LayoutAssignedWindows* layoutWindows) noexcept;
|
static void SnapNewWindowIntoZone(Layout* activeLayout, const LayoutAssignedWindows& layoutWindows) noexcept;
|
||||||
static void KeyboardSnapWindowToZone(Layout* activeLayout, LayoutAssignedWindows* layoutWindows) noexcept;
|
static void KeyboardSnapWindowToZone(Layout* activeLayout, const LayoutAssignedWindows& layoutWindows) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void SettingsTelemetry(const Settings& settings) noexcept;
|
static void SettingsTelemetry(const Settings& settings) noexcept;
|
||||||
@@ -36,8 +36,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void KeyUp(WPARAM wparam) noexcept;
|
static void KeyUp(WPARAM wparam) noexcept;
|
||||||
static void MoveOrResizeStarted(_In_opt_ Layout* activeLayout, _In_opt_ LayoutAssignedWindows* layoutWindows) noexcept;
|
static void MoveOrResizeStarted(_In_opt_ Layout* activeLayout, const LayoutAssignedWindows& layoutWindows) noexcept;
|
||||||
static void MoveOrResizeEnd(_In_opt_ Layout* activeLayout, _In_opt_ LayoutAssignedWindows* layoutWindows) noexcept;
|
static void MoveOrResizeEnd(_In_opt_ Layout* activeLayout, const LayoutAssignedWindows& layoutWindows) noexcept;
|
||||||
static void CycleActiveZoneSet(_In_opt_ Layout* activeLayout, _In_opt_ LayoutAssignedWindows* layoutWindows, InputMode mode) noexcept;
|
static void CycleActiveZoneSet(_In_opt_ Layout* activeLayout, const LayoutAssignedWindows& layoutWindows, InputMode mode) noexcept;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -123,6 +123,15 @@ namespace FancyZonesUtils
|
|||||||
monitorInfo = std::move(sortedMonitorInfo);
|
monitorInfo = std::move(sortedMonitorInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<HMONITOR> GetMonitorsOrdered()
|
||||||
|
{
|
||||||
|
auto monitors = FancyZonesUtils::GetAllMonitorRects<&MONITORINFOEX::rcWork>();
|
||||||
|
FancyZonesUtils::OrderMonitors(monitors);
|
||||||
|
std::vector<HMONITOR> output;
|
||||||
|
std::transform(std::begin(monitors), std::end(monitors), std::back_inserter(output), [](const auto& info) { return info.first; });
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsValidGuid(const std::wstring& str)
|
bool IsValidGuid(const std::wstring& str)
|
||||||
{
|
{
|
||||||
GUID id;
|
GUID id;
|
||||||
|
|||||||
@@ -143,13 +143,12 @@ namespace FancyZonesUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<RECT MONITORINFO::*member>
|
template<RECT MONITORINFO::*member>
|
||||||
RECT GetAllMonitorsCombinedRect()
|
RECT GetMonitorsCombinedRect(const std::vector<std::pair<HMONITOR, RECT>>& monitorRects)
|
||||||
{
|
{
|
||||||
auto allMonitors = GetAllMonitorRects<member>();
|
|
||||||
bool empty = true;
|
bool empty = true;
|
||||||
RECT result{ 0, 0, 0, 0 };
|
RECT result{ 0, 0, 0, 0 };
|
||||||
|
|
||||||
for (auto& [monitor, rect] : allMonitors)
|
for (auto& [monitor, rect] : monitorRects)
|
||||||
{
|
{
|
||||||
if (empty)
|
if (empty)
|
||||||
{
|
{
|
||||||
@@ -168,6 +167,13 @@ namespace FancyZonesUtils
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<RECT MONITORINFO::*member>
|
||||||
|
RECT GetAllMonitorsCombinedRect()
|
||||||
|
{
|
||||||
|
auto allMonitors = GetAllMonitorRects<member>();
|
||||||
|
return GetMonitorsCombinedRect<member>(allMonitors);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr RECT PrepareRectForCycling(RECT windowRect, RECT workAreaRect, DWORD vkCode) noexcept
|
constexpr RECT PrepareRectForCycling(RECT windowRect, RECT workAreaRect, DWORD vkCode) noexcept
|
||||||
{
|
{
|
||||||
LONG deltaX = 0, deltaY = 0;
|
LONG deltaX = 0, deltaY = 0;
|
||||||
@@ -196,6 +202,7 @@ namespace FancyZonesUtils
|
|||||||
|
|
||||||
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
|
UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
|
||||||
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
|
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
|
||||||
|
std::vector<HMONITOR> GetMonitorsOrdered();
|
||||||
|
|
||||||
bool IsValidGuid(const std::wstring& str);
|
bool IsValidGuid(const std::wstring& str);
|
||||||
std::optional<GUID> GuidFromString(const std::wstring& str) noexcept;
|
std::optional<GUID> GuidFromString(const std::wstring& str) noexcept;
|
||||||
|
|||||||
@@ -207,22 +207,22 @@ namespace FancyZonesUnitTests
|
|||||||
|
|
||||||
TEST_METHOD (AppLastZoneInvalidWindow)
|
TEST_METHOD (AppLastZoneInvalidWindow)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
|
const auto layoutId = FancyZonesUtils::GuidFromString(L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
};
|
};
|
||||||
const auto window = Mocks::Window();
|
const auto window = Mocks::Window();
|
||||||
|
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId));
|
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, layoutId));
|
||||||
|
|
||||||
const int expectedZoneIndex = 1;
|
const int expectedZoneIndex = 1;
|
||||||
Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetId, { expectedZoneIndex }));
|
Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, layoutId, { expectedZoneIndex }));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (AppLastZoneNullWindow)
|
TEST_METHOD (AppLastZoneNullWindow)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
|
const auto layoutId = FancyZonesUtils::GuidFromString(L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
@@ -230,12 +230,12 @@ namespace FancyZonesUnitTests
|
|||||||
const auto window = nullptr;
|
const auto window = nullptr;
|
||||||
|
|
||||||
const int expectedZoneIndex = 1;
|
const int expectedZoneIndex = 1;
|
||||||
Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetId, { expectedZoneIndex }));
|
Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, layoutId, { expectedZoneIndex }));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (AppLastdeviceIdTest)
|
TEST_METHOD (AppLastdeviceIdTest)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
|
const auto layoutId = FancyZonesUtils::GuidFromString(L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaId1{
|
const FancyZonesDataTypes::WorkAreaId workAreaId1{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
@@ -247,15 +247,15 @@ namespace FancyZonesUnitTests
|
|||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
const int expectedZoneIndex = 10;
|
const int expectedZoneIndex = 10;
|
||||||
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId1, zoneSetId, { expectedZoneIndex }));
|
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId1, layoutId, { expectedZoneIndex }));
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId1, zoneSetId));
|
Assert::IsTrue(std::vector<ZoneIndex>{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId1, layoutId));
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId2, zoneSetId));
|
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId2, layoutId));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (AppLastZoneSetIdTest)
|
TEST_METHOD (AppLastZoneSetIdTest)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetId1 = L"{B7A1F5A9-9DC2-4505-84AB-993253839093}";
|
const auto layoutId1 = FancyZonesUtils::GuidFromString(L"{B7A1F5A9-9DC2-4505-84AB-993253839093}").value();
|
||||||
const std::wstring zoneSetId2 = L"{B7A1F5A9-9DC2-4505-84AB-993253839094}";
|
const auto layoutId2 = FancyZonesUtils::GuidFromString(L"{B7A1F5A9-9DC2-4505-84AB-993253839094}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
@@ -263,56 +263,56 @@ namespace FancyZonesUnitTests
|
|||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
const int expectedZoneIndex = 10;
|
const int expectedZoneIndex = 10;
|
||||||
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetId1, { expectedZoneIndex }));
|
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, layoutId1, { expectedZoneIndex }));
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId1));
|
Assert::IsTrue(std::vector<ZoneIndex>{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, layoutId1));
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId2));
|
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, layoutId2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (AppLastZoneRemoveWindow)
|
TEST_METHOD (AppLastZoneRemoveWindow)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetId = L"{B7A1F5A9-9DC2-4505-84AB-993253839093}";
|
const auto layoutId = FancyZonesUtils::GuidFromString(L"{B7A1F5A9-9DC2-4505-84AB-993253839093}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
};
|
};
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetId, { 1 }));
|
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, layoutId, { 1 }));
|
||||||
Assert::IsTrue(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, zoneSetId));
|
Assert::IsTrue(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, layoutId));
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId));
|
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, layoutId));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (AppLastZoneRemoveUnknownWindow)
|
TEST_METHOD (AppLastZoneRemoveUnknownWindow)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
|
const auto layoutId = FancyZonesUtils::GuidFromString(L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
};
|
};
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, zoneSetId));
|
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, layoutId));
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId));
|
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, layoutId));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (AppLastZoneRemoveUnknownZoneSetId)
|
TEST_METHOD (AppLastZoneRemoveUnknownZoneSetId)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetIdToInsert = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
|
const auto layoutIdToInsert = FancyZonesUtils::GuidFromString(L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}").value();
|
||||||
const std::wstring zoneSetIdToRemove = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F1}";
|
const auto layoutIdToRemove = FancyZonesUtils::GuidFromString(L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F1}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
};
|
};
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetIdToInsert, { 1 }));
|
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, layoutIdToInsert, { 1 }));
|
||||||
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, zoneSetIdToRemove));
|
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, layoutIdToRemove));
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetIdToInsert));
|
Assert::IsTrue(std::vector<ZoneIndex>{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, layoutIdToInsert));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (AppLastZoneRemoveUnknownWindowId)
|
TEST_METHOD (AppLastZoneRemoveUnknownWindowId)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
|
const auto layoutId = FancyZonesUtils::GuidFromString(L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaIdToInsert{
|
const FancyZonesDataTypes::WorkAreaId workAreaIdToInsert{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
@@ -323,20 +323,20 @@ namespace FancyZonesUnitTests
|
|||||||
};
|
};
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaIdToInsert, zoneSetId, { 1 }));
|
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaIdToInsert, layoutId, { 1 }));
|
||||||
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaIdToRemove, zoneSetId));
|
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaIdToRemove, layoutId));
|
||||||
Assert::IsTrue(std::vector<ZoneIndex>{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaIdToInsert, zoneSetId));
|
Assert::IsTrue(std::vector<ZoneIndex>{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaIdToInsert, layoutId));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (AppLastZoneRemoveNullWindow)
|
TEST_METHOD (AppLastZoneRemoveNullWindow)
|
||||||
{
|
{
|
||||||
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
|
const auto layoutId = FancyZonesUtils::GuidFromString(L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}").value();
|
||||||
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
const FancyZonesDataTypes::WorkAreaId workAreaId{
|
||||||
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(nullptr, workAreaId, zoneSetId));
|
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(nullptr, workAreaId, layoutId));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,10 +140,9 @@ namespace FancyZonesUnitTests
|
|||||||
data.zoneCount = 4;
|
data.zoneCount = 4;
|
||||||
|
|
||||||
// prepare settings
|
// prepare settings
|
||||||
PowerToysSettings::PowerToyValues values(NonLocalizable::ModuleKey, NonLocalizable::ModuleKey);
|
auto settings = FancyZonesSettings::settings();
|
||||||
values.add_property(L"fancyzones_overlappingZonesAlgorithm", json::value(static_cast<int>(OverlappingZonesAlgorithm::Smallest)));
|
settings.overlappingZonesAlgorithm = OverlappingZonesAlgorithm::Smallest;
|
||||||
json::to_file(FancyZonesSettings::GetSettingsFileName(), values.get_raw_json());
|
FancyZonesSettings::instance().SetSettings(settings);
|
||||||
FancyZonesSettings::instance().LoadSettings();
|
|
||||||
|
|
||||||
auto layout = std::make_unique<Layout>(data);
|
auto layout = std::make_unique<Layout>(data);
|
||||||
layout->Init(RECT{ 0, 0, 1920, 1080 }, Mocks::Monitor());
|
layout->Init(RECT{ 0, 0, 1920, 1080 }, Mocks::Monitor());
|
||||||
@@ -168,10 +167,9 @@ namespace FancyZonesUnitTests
|
|||||||
data.zoneCount = 4;
|
data.zoneCount = 4;
|
||||||
|
|
||||||
// prepare settings
|
// prepare settings
|
||||||
PowerToysSettings::PowerToyValues values(NonLocalizable::ModuleKey, NonLocalizable::ModuleKey);
|
auto settings = FancyZonesSettings::settings();
|
||||||
values.add_property(L"fancyzones_overlappingZonesAlgorithm", json::value(static_cast<int>(OverlappingZonesAlgorithm::Smallest)));
|
settings.overlappingZonesAlgorithm = OverlappingZonesAlgorithm::Smallest;
|
||||||
json::to_file(FancyZonesSettings::GetSettingsFileName(), values.get_raw_json());
|
FancyZonesSettings::instance().SetSettings(settings);
|
||||||
FancyZonesSettings::instance().LoadSettings();
|
|
||||||
|
|
||||||
auto layout = std::make_unique<Layout>(data);
|
auto layout = std::make_unique<Layout>(data);
|
||||||
layout->Init(RECT{ 0, 0, 1920, 1080 }, Mocks::Monitor());
|
layout->Init(RECT{ 0, 0, 1920, 1080 }, Mocks::Monitor());
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Util.Spec.cpp" />
|
<ClCompile Include="Util.Spec.cpp" />
|
||||||
<ClCompile Include="Util.cpp" />
|
<ClCompile Include="Util.cpp" />
|
||||||
|
<ClCompile Include="WindowKeyboardSnap.Spec.cpp" />
|
||||||
<ClCompile Include="WorkArea.Spec.cpp" />
|
<ClCompile Include="WorkArea.Spec.cpp" />
|
||||||
<ClCompile Include="WorkAreaIdTests.Spec.cpp" />
|
<ClCompile Include="WorkAreaIdTests.Spec.cpp" />
|
||||||
<ClCompile Include="Zone.Spec.cpp" />
|
<ClCompile Include="Zone.Spec.cpp" />
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
<ClCompile Include="DefaultLayoutsTests.Spec.cpp">
|
<ClCompile Include="DefaultLayoutsTests.Spec.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="WindowKeyboardSnap.Spec.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="pch.h">
|
<ClInclude Include="pch.h">
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,6 @@ namespace FancyZonesUnitTests
|
|||||||
{
|
{
|
||||||
std::filesystem::remove(AppliedLayouts::AppliedLayoutsFileName());
|
std::filesystem::remove(AppliedLayouts::AppliedLayoutsFileName());
|
||||||
std::filesystem::remove(AppZoneHistory::AppZoneHistoryFileName());
|
std::filesystem::remove(AppZoneHistory::AppZoneHistoryFileName());
|
||||||
|
|
||||||
std::filesystem::remove(DefaultLayouts::DefaultLayoutsFileName());
|
std::filesystem::remove(DefaultLayouts::DefaultLayoutsFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +57,6 @@ namespace FancyZonesUnitTests
|
|||||||
|
|
||||||
const auto& layout = workArea->GetLayout();
|
const auto& layout = workArea->GetLayout();
|
||||||
Assert::IsNotNull(layout.get());
|
Assert::IsNotNull(layout.get());
|
||||||
Assert::IsNotNull(workArea->GetLayoutWindows().get());
|
|
||||||
Assert::AreEqual(static_cast<int>(defaultLayout.type), static_cast<int>(layout->Type()));
|
Assert::AreEqual(static_cast<int>(defaultLayout.type), static_cast<int>(layout->Type()));
|
||||||
Assert::AreEqual(defaultLayout.zoneCount, static_cast<int>(layout->Zones().size()));
|
Assert::AreEqual(defaultLayout.zoneCount, static_cast<int>(layout->Zones().size()));
|
||||||
}
|
}
|
||||||
@@ -73,7 +71,6 @@ namespace FancyZonesUnitTests
|
|||||||
|
|
||||||
const auto& layout = workArea->GetLayout();
|
const auto& layout = workArea->GetLayout();
|
||||||
Assert::IsNotNull(layout.get());
|
Assert::IsNotNull(layout.get());
|
||||||
Assert::IsNotNull(workArea->GetLayoutWindows().get());
|
|
||||||
Assert::AreEqual(static_cast<int>(defaultLayout.type), static_cast<int>(layout->Type()));
|
Assert::AreEqual(static_cast<int>(defaultLayout.type), static_cast<int>(layout->Type()));
|
||||||
Assert::AreEqual(defaultLayout.zoneCount, static_cast<int>(layout->Zones().size()));
|
Assert::AreEqual(defaultLayout.zoneCount, static_cast<int>(layout->Zones().size()));
|
||||||
}
|
}
|
||||||
@@ -102,7 +99,6 @@ namespace FancyZonesUnitTests
|
|||||||
|
|
||||||
auto actualWorkArea = WorkArea::Create(m_hInst, m_workAreaId, parentUniqueId, m_workAreaRect);
|
auto actualWorkArea = WorkArea::Create(m_hInst, m_workAreaId, parentUniqueId, m_workAreaRect);
|
||||||
Assert::IsNotNull(actualWorkArea->GetLayout().get());
|
Assert::IsNotNull(actualWorkArea->GetLayout().get());
|
||||||
Assert::IsNotNull(actualWorkArea->GetLayoutWindows().get());
|
|
||||||
|
|
||||||
Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().contains(m_workAreaId));
|
Assert::IsTrue(AppliedLayouts::instance().GetAppliedLayoutMap().contains(m_workAreaId));
|
||||||
const auto& actualLayout = AppliedLayouts::instance().GetAppliedLayoutMap().at(m_workAreaId);
|
const auto& actualLayout = AppliedLayouts::instance().GetAppliedLayoutMap().at(m_workAreaId);
|
||||||
@@ -179,428 +175,46 @@ namespace FancyZonesUnitTests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CLASS (WorkAreaMoveWindowUnitTests)
|
TEST_CLASS (WorkAreaSnapUnitTests)
|
||||||
{
|
{
|
||||||
const std::wstring m_virtualDesktopIdStr = L"{A998CA86-F08D-4BCA-AED8-77F5C8FC9925}";
|
HINSTANCE m_hInst{};
|
||||||
const FancyZonesDataTypes::WorkAreaId m_workAreaId{
|
const HMONITOR m_monitor = Mocks::Monitor();
|
||||||
|
const FancyZonesUtils::Rect m_workAreaRect{ RECT(0, 0, 1920, 1080) };
|
||||||
|
const FancyZonesDataTypes::WorkAreaId m_parentUniqueId = {};
|
||||||
|
const FancyZonesDataTypes::WorkAreaId m_workAreaId = {
|
||||||
.monitorId = {
|
.monitorId = {
|
||||||
.monitor = Mocks::Monitor(),
|
.monitor = m_monitor,
|
||||||
.deviceId = {
|
.deviceId = {
|
||||||
.id = L"DELA026",
|
.id = L"device-id-1",
|
||||||
.instanceId = L"5&10a58c63&0&UID16777488",
|
.instanceId = L"5&10a58c63&0&UID16777488",
|
||||||
.number = 1,
|
.number = 1,
|
||||||
},
|
},
|
||||||
.serialNumber = L"serial-number"
|
.serialNumber = L"serial-number-1" },
|
||||||
},
|
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{310F2924-B587-4D87-97C2-90031BDBE3F1}").value()
|
||||||
.virtualDesktopId = FancyZonesUtils::GuidFromString(m_virtualDesktopIdStr).value()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FancyZonesDataTypes::WorkAreaId m_parentUniqueId; // default empty
|
|
||||||
|
|
||||||
HINSTANCE m_hInst{};
|
|
||||||
FancyZonesUtils::Rect m_workAreaRect{ RECT(0, 0, 1920, 1080) };
|
|
||||||
|
|
||||||
void PrepareEmptyLayout()
|
|
||||||
{
|
|
||||||
json::JsonObject root{};
|
|
||||||
json::JsonArray layoutsArray{};
|
|
||||||
|
|
||||||
{
|
|
||||||
json::JsonObject layout{};
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::UuidID, json::value(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}"));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::TypeID, json::value(FancyZonesDataTypes::TypeToString(FancyZonesDataTypes::ZoneSetLayoutType::Blank)));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ShowSpacingID, json::value(false));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SpacingID, json::value(0));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ZoneCountID, json::value(0));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(0));
|
|
||||||
|
|
||||||
json::JsonObject workAreaId{};
|
|
||||||
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{};
|
|
||||||
obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::DeviceID, workAreaId);
|
|
||||||
obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID, layout);
|
|
||||||
|
|
||||||
layoutsArray.Append(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
root.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID, layoutsArray);
|
|
||||||
json::to_file(AppliedLayouts::AppliedLayoutsFileName(), root);
|
|
||||||
|
|
||||||
AppliedLayouts::instance().LoadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrepareGridLayout()
|
|
||||||
{
|
|
||||||
json::JsonObject root{};
|
|
||||||
json::JsonArray layoutsArray{};
|
|
||||||
|
|
||||||
{
|
|
||||||
json::JsonObject layout{};
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::UuidID, json::value(L"{ACE817FD-2C51-4E13-903A-84CAB86FD17C}"));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::TypeID, json::value(FancyZonesDataTypes::TypeToString(FancyZonesDataTypes::ZoneSetLayoutType::Grid)));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ShowSpacingID, json::value(false));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SpacingID, json::value(0));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ZoneCountID, json::value(4));
|
|
||||||
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(20));
|
|
||||||
|
|
||||||
json::JsonObject workAreaId{};
|
|
||||||
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{};
|
|
||||||
obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::DeviceID, workAreaId);
|
|
||||||
obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID, layout);
|
|
||||||
|
|
||||||
layoutsArray.Append(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
root.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID, layoutsArray);
|
|
||||||
json::to_file(AppliedLayouts::AppliedLayoutsFileName(), root);
|
|
||||||
|
|
||||||
AppliedLayouts::instance().LoadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD_INITIALIZE(Init) noexcept
|
TEST_METHOD_INITIALIZE(Init) noexcept
|
||||||
{
|
{
|
||||||
AppZoneHistory::instance().LoadData();
|
AppZoneHistory::instance().LoadData();
|
||||||
AppliedLayouts::instance().LoadData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD_CLEANUP(CleanUp) noexcept
|
TEST_METHOD_CLEANUP(CleanUp) noexcept
|
||||||
{
|
{
|
||||||
std::filesystem::remove(AppZoneHistory::AppZoneHistoryFileName());
|
std::filesystem::remove(AppZoneHistory::AppZoneHistoryFileName());
|
||||||
std::filesystem::remove(AppliedLayouts::AppliedLayoutsFileName());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (EmptyZonesMoveLeftByIndex)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareEmptyLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)0, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{} == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (EmptyZonesRightByIndex)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareEmptyLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)0, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{} == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveLeftNonAppliedWindowByIndex)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 3 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveRightNonAppliedWindowByIndex)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowByIndex)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
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
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_RIGHT, true);
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 1 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowByIndexCycle)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
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
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ static_cast<ZoneIndex>(workArea->GetLayout()->Zones().size() - 1) } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowByIndexNoCycle)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
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
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, false);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (EmptyZonesMoveByPosition)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareEmptyLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_LEFT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)0, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{} == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveLeftNonAppliedWindowByPosition)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_LEFT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 1 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveRightNonAppliedWindowByPosition)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_RIGHT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowHorizontallyByPosition)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, { 0 }, true); // snap to the 1st zone
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_RIGHT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 1 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowVerticallyByPosition)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, { 0 }, true); // snap to the 1st zone
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_DOWN, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 2 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowByPositionHorizontallyCycle)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, { 0 }, true); // snap to the 1st zone
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_LEFT, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 1 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowByPositionHorizontallyNoCycle)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
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
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_LEFT, false);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowByPositionVerticallyCycle)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
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->MoveWindowIntoZoneByIndexSet(window, { 0 }, true); // snap to the 1st zone
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_UP, true);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 2 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (MoveAppliedWindowByPositionVerticallyNoCycle)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, { 0 }, true); // snap to the 1st zone
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndPosition(window, VK_UP, false);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (ExtendZoneHorizontally)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, { 0 }, true); // snap to the 1st zone
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->ExtendWindowByDirectionAndPosition(window, VK_RIGHT);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0, 1 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_METHOD (ExtendZoneVertically)
|
|
||||||
{
|
|
||||||
// prepare
|
|
||||||
PrepareGridLayout();
|
|
||||||
auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
|
||||||
workArea->MoveWindowIntoZoneByIndexSet(window, { 0 }, true); // snap to the 1st zone
|
|
||||||
|
|
||||||
// test
|
|
||||||
workArea->ExtendWindowByDirectionAndPosition(window, VK_DOWN);
|
|
||||||
|
|
||||||
const auto& actualAppZoneHistory = AppZoneHistory::instance().GetFullAppZoneHistory();
|
|
||||||
Assert::AreEqual((size_t)1, actualAppZoneHistory.size());
|
|
||||||
|
|
||||||
const auto& layoutWindows = workArea->GetLayoutWindows();
|
|
||||||
Assert::IsTrue(ZoneIndexSet{ 0, 2 } == layoutWindows->GetZoneIndexSetFromWindow(window));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt)
|
TEST_METHOD (WhenWindowIsNotResizablePlacingItIntoTheZoneShouldNotResizeIt)
|
||||||
{
|
{
|
||||||
|
LayoutData layout{
|
||||||
|
.uuid = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC58}").value(),
|
||||||
|
.type = FancyZonesDataTypes::ZoneSetLayoutType::Grid,
|
||||||
|
.showSpacing = false,
|
||||||
|
.spacing = 0,
|
||||||
|
.zoneCount = 4,
|
||||||
|
.sensitivityRadius = 20,
|
||||||
|
};
|
||||||
|
AppliedLayouts::instance().ApplyLayout(m_workAreaId, layout);
|
||||||
|
|
||||||
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
@@ -610,7 +224,10 @@ namespace FancyZonesUnitTests
|
|||||||
SetWindowPos(window, nullptr, 150, 150, originalWidth, originalHeight, SWP_SHOWWINDOW);
|
SetWindowPos(window, nullptr, 150, 150, originalWidth, originalHeight, SWP_SHOWWINDOW);
|
||||||
SetWindowLong(window, GWL_STYLE, GetWindowLong(window, GWL_STYLE) & ~WS_SIZEBOX);
|
SetWindowLong(window, GWL_STYLE, GetWindowLong(window, GWL_STYLE) & ~WS_SIZEBOX);
|
||||||
|
|
||||||
workArea->MoveWindowIntoZoneByDirectionAndIndex(window, VK_LEFT, true);
|
Assert::IsTrue(workArea->Snap(window, { 1 }, true));
|
||||||
|
|
||||||
|
// wait for the window to be resized
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
RECT inZoneRect;
|
RECT inZoneRect;
|
||||||
GetWindowRect(window, &inZoneRect);
|
GetWindowRect(window, &inZoneRect);
|
||||||
@@ -619,13 +236,46 @@ namespace FancyZonesUnitTests
|
|||||||
Assert::AreEqual(originalHeight, (int)inZoneRect.bottom - (int)inZoneRect.top);
|
Assert::AreEqual(originalHeight, (int)inZoneRect.bottom - (int)inZoneRect.top);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_METHOD (WhenWindowIsResizablePlacingItIntoTheZoneShouldResizeIt)
|
||||||
|
{
|
||||||
|
LayoutData layout{
|
||||||
|
.uuid = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC58}").value(),
|
||||||
|
.type = FancyZonesDataTypes::ZoneSetLayoutType::Grid,
|
||||||
|
.showSpacing = false,
|
||||||
|
.spacing = 0,
|
||||||
|
.zoneCount = 4,
|
||||||
|
.sensitivityRadius = 20,
|
||||||
|
};
|
||||||
|
AppliedLayouts::instance().ApplyLayout(m_workAreaId, layout);
|
||||||
|
|
||||||
|
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
||||||
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
|
SetWindowPos(window, nullptr, 150, 150, 450, 550, SWP_SHOWWINDOW);
|
||||||
|
|
||||||
|
Assert::IsTrue(workArea->Snap(window, { 1 }, true));
|
||||||
|
|
||||||
|
// wait for the window to be resized
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
|
RECT zonedWindowRect;
|
||||||
|
GetWindowRect(window, &zonedWindowRect);
|
||||||
|
|
||||||
|
RECT zoneRect = workArea->GetLayout()->Zones().at(1).GetZoneRect();
|
||||||
|
|
||||||
|
Assert::AreEqual(zoneRect.left, zonedWindowRect.left);
|
||||||
|
Assert::AreEqual(zoneRect.right, zonedWindowRect.right);
|
||||||
|
Assert::AreEqual(zoneRect.top, zonedWindowRect.top);
|
||||||
|
Assert::AreEqual(zoneRect.bottom, zonedWindowRect.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_METHOD (SnapWindowPropertyTest)
|
TEST_METHOD (SnapWindowPropertyTest)
|
||||||
{
|
{
|
||||||
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
const ZoneIndexSet expected = { 1, 2 };
|
const ZoneIndexSet expected = { 1, 2 };
|
||||||
workArea->SnapWindow(window, expected);
|
Assert::IsTrue(workArea->Snap(window, expected));
|
||||||
|
|
||||||
const auto actual = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
|
const auto actual = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
|
||||||
Assert::AreEqual(expected.size(), actual.size());
|
Assert::AreEqual(expected.size(), actual.size());
|
||||||
@@ -641,7 +291,7 @@ namespace FancyZonesUnitTests
|
|||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
const ZoneIndexSet expected = { 1, 2 };
|
const ZoneIndexSet expected = { 1, 2 };
|
||||||
workArea->SnapWindow(window, expected);
|
Assert::IsTrue(workArea->Snap(window, expected));
|
||||||
|
|
||||||
const auto processPath = get_process_path(window);
|
const auto processPath = get_process_path(window);
|
||||||
const auto history = AppZoneHistory::instance().GetZoneHistory(processPath, m_workAreaId);
|
const auto history = AppZoneHistory::instance().GetZoneHistory(processPath, m_workAreaId);
|
||||||
@@ -654,13 +304,25 @@ namespace FancyZonesUnitTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_METHOD (SnapLayoutAssignedWindowsTest)
|
||||||
|
{
|
||||||
|
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 };
|
||||||
|
Assert::IsTrue(workArea->Snap(window, expected));
|
||||||
|
|
||||||
|
const auto& layoutWindows = workArea->GetLayoutWindows();
|
||||||
|
Assert::IsTrue(expected == layoutWindows.GetZoneIndexSetFromWindow(window));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_METHOD (UnsnapPropertyTest)
|
TEST_METHOD (UnsnapPropertyTest)
|
||||||
{
|
{
|
||||||
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
workArea->SnapWindow(window, { 1, 2 });
|
Assert::IsTrue(workArea->Snap(window, { 1, 2 }));
|
||||||
workArea->UnsnapWindow(window);
|
Assert::IsTrue(workArea->Unsnap(window));
|
||||||
|
|
||||||
const auto actual = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
|
const auto actual = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
|
||||||
Assert::IsTrue(actual.empty());
|
Assert::IsTrue(actual.empty());
|
||||||
@@ -671,13 +333,25 @@ namespace FancyZonesUnitTests
|
|||||||
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
||||||
const auto window = Mocks::WindowCreate(m_hInst);
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
workArea->SnapWindow(window, { 1, 2 });
|
Assert::IsTrue(workArea->Snap(window, { 1, 2 }));
|
||||||
workArea->UnsnapWindow(window);
|
Assert::IsTrue(workArea->Unsnap(window));
|
||||||
|
|
||||||
const auto processPath = get_process_path(window);
|
const auto processPath = get_process_path(window);
|
||||||
const auto history = AppZoneHistory::instance().GetZoneHistory(processPath, m_workAreaId);
|
const auto history = AppZoneHistory::instance().GetZoneHistory(processPath, m_workAreaId);
|
||||||
|
|
||||||
Assert::IsFalse(history.has_value());
|
Assert::IsFalse(history.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_METHOD (UnsnapLayoutAssignedWindowsTest)
|
||||||
|
{
|
||||||
|
const auto workArea = WorkArea::Create(m_hInst, m_workAreaId, m_parentUniqueId, m_workAreaRect);
|
||||||
|
const auto window = Mocks::WindowCreate(m_hInst);
|
||||||
|
|
||||||
|
Assert::IsTrue(workArea->Snap(window, { 1, 2 }));
|
||||||
|
Assert::IsTrue(workArea->Unsnap(window));
|
||||||
|
|
||||||
|
const auto& layoutWindows = workArea->GetLayoutWindows();
|
||||||
|
Assert::IsTrue(layoutWindows.GetZoneIndexSetFromWindow(window).empty());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user