[FancyZones] Improve code quality (part 6) (#28034)

This commit is contained in:
Seraphima Zykova
2023-08-22 15:57:45 +03:00
committed by GitHub
parent 7c7f6cabf7
commit 6acae53e2c
29 changed files with 2669 additions and 1239 deletions

View File

@@ -26,7 +26,8 @@
#include <FancyZonesLib/Settings.h>
#include <FancyZonesLib/SettingsObserver.h>
#include <FancyZonesLib/trace.h>
#include <FancyZonesLib/WindowDrag.h>
#include <FancyZonesLib/WindowKeyboardSnap.h>
#include <FancyZonesLib/WindowMouseSnap.h>
#include <FancyZonesLib/WorkArea.h>
enum class DisplayChangeType
@@ -142,10 +143,6 @@ protected:
private:
void UpdateWorkAreas(bool updateWindowPositions) 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;
@@ -153,13 +150,11 @@ private:
bool MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept;
void UpdateActiveLayouts() noexcept;
void RefreshLayouts() noexcept;
bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept;
void ApplyQuickLayout(int key) noexcept;
void FlashZones() noexcept;
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
HMONITOR WorkAreaKeyFromWindow(HWND window) noexcept;
virtual void SettingsUpdate(SettingId type) override;
@@ -167,7 +162,8 @@ private:
const HINSTANCE m_hinstance{};
HWND m_window{};
std::unique_ptr<WindowDrag> m_windowDrag{};
std::unique_ptr<WindowMouseSnap> m_windowMouseSnapper{};
WindowKeyboardSnap m_windowKeyboardSnapper{};
MonitorWorkAreaMap m_workAreaHandler;
DraggingState m_draggingState;
@@ -288,8 +284,8 @@ FancyZones::VirtualDesktopChanged() noexcept
void FancyZones::MoveSizeStart(HWND window, HMONITOR monitor)
{
m_windowDrag = WindowDrag::Create(window, m_workAreaHandler.GetAllWorkAreas());
if (m_windowDrag)
m_windowMouseSnapper = WindowMouseSnap::Create(window, m_workAreaHandler.GetAllWorkAreas());
if (m_windowMouseSnapper)
{
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
{
@@ -298,13 +294,13 @@ void FancyZones::MoveSizeStart(HWND window, HMONITOR monitor)
m_draggingState.Enable();
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)
{
if (m_windowDrag)
if (m_windowMouseSnapper)
{
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
{
@@ -312,17 +308,17 @@ void FancyZones::MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen)
}
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()
{
if (m_windowDrag)
if (m_windowMouseSnapper)
{
m_windowDrag->MoveSizeEnd();
m_windowMouseSnapper->MoveSizeEnd();
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();
if (workArea)
{
indexes = workArea->GetWindowZoneIndexes(window);
indexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workArea->UniqueId(), workArea->GetLayoutId());
}
}
else
@@ -353,7 +349,7 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept
{
if (secondaryWorkArea)
{
indexes = secondaryWorkArea->GetWindowZoneIndexes(window);
indexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, secondaryWorkArea->UniqueId(), secondaryWorkArea->GetLayoutId());
workArea = secondaryWorkArea.get();
if (!indexes.empty())
{
@@ -365,8 +361,8 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept
if (!indexes.empty() && workArea)
{
Trace::FancyZones::SnapNewWindowIntoZone(workArea->GetLayout().get(), workArea->GetLayoutWindows().get());
workArea->MoveWindowIntoZoneByIndexSet(window, indexes);
Trace::FancyZones::SnapNewWindowIntoZone(workArea->GetLayout().get(), workArea->GetLayoutWindows());
workArea->Snap(window, indexes);
return true;
}
@@ -604,7 +600,40 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
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)
{
@@ -661,7 +690,7 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
else if (message == WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE)
{
AppliedLayouts::instance().LoadData();
UpdateActiveLayouts();
RefreshLayouts();
}
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)
{
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 monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
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);
}
else
@@ -829,10 +858,10 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept
{
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)
{
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
{
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())
{
if (workArea)
{
workArea->UpdateActiveZoneSet();
workArea->InitLayout();
if (FancyZonesSettings::settings().zoneSetChange_moveWindows)
{
@@ -1265,7 +1043,7 @@ void FancyZones::ApplyQuickLayout(int key) noexcept
{
AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), layout.value());
AppliedLayouts::instance().SaveData();
UpdateActiveLayouts();
RefreshLayouts();
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
{
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)