[FancyZones] Added persistence to app zone history (#3132)

* Persist app zone history in a separate file

* Almost ready to be functionally tested

* Now all unit tests pass

* Bug fixes, it seems to work

* Various fixups

* Improved performance of FancyZones::UpdateWindowsPositions()
This commit is contained in:
Ivan Stošić
2020-05-26 16:01:12 +02:00
committed by GitHub
parent bc9add783c
commit 6f22c7ad19
17 changed files with 349 additions and 881 deletions

View File

@@ -363,10 +363,10 @@ FancyZones::WindowCreated(HWND window) noexcept
wil::unique_cotaskmem_string guidString;
if (SUCCEEDED(StringFromCLSID(activeZoneSet->Id(), &guidString)))
{
int zoneIndex = fancyZonesData.GetAppLastZoneIndex(window, zoneWindow->UniqueId(), guidString.get());
if (zoneIndex != -1)
std::vector<int> zoneIndexSet = fancyZonesData.GetAppLastZoneIndexSet(window, zoneWindow->UniqueId(), guidString.get());
if (zoneIndexSet.size())
{
m_windowMoveHandler.MoveWindowIntoZoneByIndex(window, monitor, zoneIndex, m_zoneWindowMap);
m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, monitor, zoneIndexSet, m_zoneWindowMap);
break;
}
}
@@ -790,13 +790,22 @@ void FancyZones::UpdateZoneWindows() noexcept
void FancyZones::UpdateWindowsPositions() noexcept
{
auto callback = [](HWND window, LPARAM data) -> BOOL {
int i = static_cast<int>(reinterpret_cast<UINT_PTR>(::GetProp(window, ZONE_STAMP)));
if (i != 0)
size_t bitmask = reinterpret_cast<size_t>(::GetProp(window, MULTI_ZONE_STAMP));
if (bitmask != 0)
{
// i is off by 1 since 0 is special.
std::vector<int> indexSet;
for (int i = 0; i < std::numeric_limits<size_t>::digits; i++)
{
if ((1ull << i) & bitmask)
{
indexSet.push_back(i);
}
}
auto strongThis = reinterpret_cast<FancyZones*>(data);
std::unique_lock writeLock(strongThis->m_lock);
strongThis->m_windowMoveHandler.MoveWindowIntoZoneByIndex(window, nullptr, i - 1, strongThis->m_zoneWindowMap);
strongThis->m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, nullptr, indexSet, strongThis->m_zoneWindowMap);
}
return TRUE;
};

View File

@@ -23,6 +23,7 @@ namespace
constexpr int c_blankCustomModelId = 0xFFFA;
const wchar_t* FANCY_ZONES_DATA_FILE = L"zones-settings.json";
const wchar_t* FANCY_ZONES_APP_ZONE_HISTORY_FILE = L"app-zone-history.json";
const wchar_t* DEFAULT_GUID = L"{00000000-0000-0000-0000-000000000000}";
const wchar_t* REG_SETTINGS = L"Software\\SuperFancyZones";
@@ -221,6 +222,7 @@ namespace JSONHelpers
{
std::wstring result = PTSettingsHelper::get_module_save_folder_location(L"FancyZones");
jsonFilePath = result + L"\\" + std::wstring(FANCY_ZONES_DATA_FILE);
appZoneHistoryFilePath = result + L"\\" + std::wstring(FANCY_ZONES_APP_ZONE_HISTORY_FILE);
}
json::JsonObject FancyZonesData::GetPersistFancyZonesJSON()
@@ -232,6 +234,18 @@ namespace JSONHelpers
auto result = json::from_file(save_file_path);
if (result)
{
if (!result->HasKey(L"app-zone-history"))
{
auto appZoneHistory = json::from_file(appZoneHistoryFilePath);
if (appZoneHistory)
{
result->SetNamedValue(L"app-zone-history", appZoneHistory->GetNamedArray(L"app-zone-history"));
}
else
{
result->SetNamedValue(L"app-zone-history", json::JsonArray());
}
}
return *result;
}
else
@@ -368,7 +382,7 @@ namespace JSONHelpers
SaveFancyZonesData();
}
int FancyZonesData::GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const
std::vector<int> FancyZonesData::GetAppLastZoneIndexSet(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const
{
std::scoped_lock lock{ dataLock };
auto processPath = get_process_path(window);
@@ -380,12 +394,12 @@ namespace JSONHelpers
const auto& data = history->second;
if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId)
{
return history->second.zoneIndex;
return history->second.zoneIndexSet;
}
}
}
return -1;
return {};
}
bool FancyZonesData::RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId)
@@ -410,7 +424,7 @@ namespace JSONHelpers
return false;
}
bool FancyZonesData::SetAppLastZone(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, int zoneIndex)
bool FancyZonesData::SetAppLastZones(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, const std::vector<int>& zoneIndexSet)
{
std::scoped_lock lock{ dataLock };
auto processPath = get_process_path(window);
@@ -419,7 +433,7 @@ namespace JSONHelpers
return false;
}
appZoneHistoryMap[processPath] = AppZoneHistoryData{ .zoneSetUuid = zoneSetId, .deviceId = deviceId, .zoneIndex = zoneIndex };
appZoneHistoryMap[processPath] = AppZoneHistoryData{ .zoneSetUuid = zoneSetId, .deviceId = deviceId, .zoneIndexSet = zoneIndexSet };
SaveFancyZonesData();
return true;
}
@@ -669,8 +683,9 @@ namespace JSONHelpers
{
std::scoped_lock lock{ dataLock };
json::JsonObject root{};
json::JsonObject appZoneHistoryRoot{};
root.SetNamedValue(L"app-zone-history", SerializeAppZoneHistory());
appZoneHistoryRoot.SetNamedValue(L"app-zone-history", SerializeAppZoneHistory());
root.SetNamedValue(L"devices", SerializeDeviceInfos());
root.SetNamedValue(L"custom-zone-sets", SerializeCustomZoneSets());
@@ -681,6 +696,7 @@ namespace JSONHelpers
}
json::to_file(jsonFilePath, root);
json::to_file(appZoneHistoryFilePath, appZoneHistoryRoot);
}
void FancyZonesData::MigrateCustomZoneSetsFromRegistry()
@@ -817,7 +833,14 @@ namespace JSONHelpers
json::JsonObject result{};
result.SetNamedValue(L"app-path", json::value(appZoneHistory.appPath));
result.SetNamedValue(L"zone-index", json::value(appZoneHistory.data.zoneIndex));
json::JsonArray jsonIndexSet;
for (int index : appZoneHistory.data.zoneIndexSet)
{
jsonIndexSet.Append(json::value(index));
}
result.SetNamedValue(L"zone-index-set", jsonIndexSet);
result.SetNamedValue(L"device-id", json::value(appZoneHistory.data.deviceId));
result.SetNamedValue(L"zoneset-uuid", json::value(appZoneHistory.data.zoneSetUuid));
@@ -831,7 +854,19 @@ namespace JSONHelpers
AppZoneHistoryJSON result;
result.appPath = zoneSet.GetNamedString(L"app-path");
result.data.zoneIndex = static_cast<int>(zoneSet.GetNamedNumber(L"zone-index"));
if (zoneSet.HasKey(L"zone-index-set"))
{
result.data.zoneIndexSet = {};
for (auto& value : zoneSet.GetNamedArray(L"zone-index-set"))
{
result.data.zoneIndexSet.push_back(static_cast<int>(value.GetNumber()));
}
}
else if (zoneSet.HasKey(L"zone-index"))
{
result.data.zoneIndexSet = { static_cast<int>(zoneSet.GetNamedNumber(L"zone-index")) };
}
result.data.deviceId = zoneSet.GetNamedString(L"device-id");
result.data.zoneSetUuid = zoneSet.GetNamedString(L"zoneset-uuid");

View File

@@ -134,7 +134,7 @@ namespace JSONHelpers
{
std::wstring zoneSetUuid;
std::wstring deviceId;
int zoneIndex;
std::vector<int> zoneIndexSet;
};
struct AppZoneHistoryJSON
@@ -174,6 +174,12 @@ namespace JSONHelpers
{
return jsonFilePath;
}
inline const std::wstring& GetPersistAppZoneHistoryFilePath() const
{
return appZoneHistoryFilePath;
}
json::JsonObject GetPersistFancyZonesJSON();
std::optional<DeviceInfoData> FindDeviceInfo(const std::wstring& zoneWindowId) const;
@@ -236,9 +242,9 @@ namespace JSONHelpers
void UpdatePrimaryDesktopData(const std::wstring& desktopId);
void RemoveDeletedDesktops(const std::vector<std::wstring>& activeDesktops);
int GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const;
std::vector<int> GetAppLastZoneIndexSet(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const;
bool RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId);
bool SetAppLastZone(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, int zoneIndex);
bool SetAppLastZones(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, const std::vector<int>& zoneIndexSet);
void SetActiveZoneSet(const std::wstring& deviceId, const ZoneSetData& zoneSet);
@@ -268,6 +274,7 @@ namespace JSONHelpers
std::wstring activeDeviceId;
std::wstring jsonFilePath;
std::wstring appZoneHistoryFilePath;
};
FancyZonesData& FancyZonesDataInstance();

View File

@@ -1,6 +1,6 @@
#pragma once
#define ZONE_STAMP L"FancyZones_zone"
#define MULTI_ZONE_STAMP L"FancyZones_zones"
#include <common/settings_objects.h>
struct Settings

View File

@@ -116,9 +116,9 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st
pimpl->MoveSizeEnd(window, ptScreen, zoneWindowMap);
}
void WindowMoveHandler::MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
void WindowMoveHandler::MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept
{
pimpl->MoveWindowIntoZoneByIndexSet(window, monitor, { index }, zoneWindowMap);
pimpl->MoveWindowIntoZoneByIndexSet(window, monitor, indexSet, zoneWindowMap);
}
bool WindowMoveHandler::MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap)
@@ -256,7 +256,7 @@ void WindowMoveHandlerPrivate::MoveSizeEnd(HWND window, POINT const& ptScreen, c
}
else
{
::RemoveProp(window, ZONE_STAMP);
::RemoveProp(window, MULTI_ZONE_STAMP);
auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)

View File

@@ -16,7 +16,7 @@ public:
void MoveSizeUpdate(HMONITOR monitor, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveSizeEnd(HWND window, POINT const& ptScreen, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveWindowIntoZoneByIndex(HWND window, HMONITOR monitor, int index, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
void MoveWindowIntoZoneByIndexSet(HWND window, HMONITOR monitor, const std::vector<int>& indexSet, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap) noexcept;
bool MoveWindowIntoZoneByDirection(HMONITOR monitor, HWND window, DWORD vkCode, bool cycle, const std::map<HMONITOR, winrt::com_ptr<IZoneWindow>>& zoneWindowMap);
private:

View File

@@ -20,57 +20,16 @@ public:
}
IFACEMETHODIMP_(RECT) GetZoneRect() noexcept { return m_zoneRect; }
IFACEMETHODIMP_(bool) IsEmpty() noexcept { return m_windows.empty(); };
IFACEMETHODIMP_(bool) ContainsWindow(HWND window) noexcept;
IFACEMETHODIMP_(void) AddWindowToZone(HWND window, HWND zoneWindow, bool stampZone) noexcept;
IFACEMETHODIMP_(void) RemoveWindowFromZone(HWND window, bool restoreSize) noexcept;
IFACEMETHODIMP_(void) SetId(size_t id) noexcept { m_id = id; }
IFACEMETHODIMP_(size_t) Id() noexcept { return m_id; }
IFACEMETHODIMP_(RECT) ComputeActualZoneRect(HWND window, HWND zoneWindow) noexcept;
private:
void SizeWindowToZone(HWND window, HWND zoneWindow) noexcept;
void StampZone(HWND window, bool stamp) noexcept;
RECT m_zoneRect{};
size_t m_id{};
std::map<HWND, RECT> m_windows{};
};
IFACEMETHODIMP_(bool) Zone::ContainsWindow(HWND window) noexcept
{
return (m_windows.find(window) != m_windows.end());
}
IFACEMETHODIMP_(void) Zone::AddWindowToZone(HWND window, HWND zoneWindow, bool stampZone) noexcept
{
WINDOWPLACEMENT placement;
::GetWindowPlacement(window, &placement);
::GetWindowRect(window, &placement.rcNormalPosition);
m_windows.emplace(std::pair<HWND, RECT>(window, placement.rcNormalPosition));
SizeWindowToZone(window, zoneWindow);
if (stampZone)
{
StampZone(window, true);
}
}
IFACEMETHODIMP_(void) Zone::RemoveWindowFromZone(HWND window, bool restoreSize) noexcept
{
auto iter = m_windows.find(window);
if (iter != m_windows.end())
{
m_windows.erase(iter);
StampZone(window, false);
}
}
void Zone::SizeWindowToZone(HWND window, HWND zoneWindow) noexcept
{
SizeWindowToRect(window, ComputeActualZoneRect(window, zoneWindow));
}
static BOOL CALLBACK saveDisplayToVector(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM data)
{
reinterpret_cast<std::vector<HMONITOR>*>(data)->emplace_back(monitor);
@@ -161,18 +120,6 @@ RECT Zone::ComputeActualZoneRect(HWND window, HWND zoneWindow) noexcept
return newWindowRect;
}
void Zone::StampZone(HWND window, bool stamp) noexcept
{
if (stamp)
{
SetProp(window, ZONE_STAMP, reinterpret_cast<HANDLE>(m_id));
}
else
{
RemoveProp(window, ZONE_STAMP);
}
}
winrt::com_ptr<IZone> MakeZone(const RECT& zoneRect) noexcept
{
return winrt::make_self<Zone>(zoneRect);

View File

@@ -9,34 +9,6 @@ interface __declspec(uuid("{8228E934-B6EF-402A-9892-15A1441BF8B0}")) IZone : pub
* @returns Zone coordinates (top-left and bottom-right corner) represented as RECT structure.
*/
IFACEMETHOD_(RECT, GetZoneRect)() = 0;
/**
* @returns Boolean indicating if zone is empty or there are windows assigned to it.
*/
IFACEMETHOD_(bool, IsEmpty)() = 0;
/**
* @param window Window handle.
* @returns Boolean indicating if specified window is assigned to the zone.
*/
IFACEMETHOD_(bool, ContainsWindow)(HWND window) = 0;
/**
* Assign single window to this zone.
*
* @param window Handle of window which should be assigned to zone.
* @param zoneWindow The m_window of a ZoneWindow, it's a hidden window representing the
* current monitor desktop work area.
* @param stampZone Boolean indicating weather we should add special property on the
* window. This property is used on display change to rearrange windows
* to corresponding zones.
*/
IFACEMETHOD_(void, AddWindowToZone)(HWND window, HWND zoneWindow, bool stampZone) = 0;
/**
* Remove window from this zone (if it is assigned to it).
*
* @param window Handle of window to be removed from this zone.
* @param restoreSize Boolean indicating that window should fall back to dimensions
* before assigning to this zone.
*/
IFACEMETHOD_(void, RemoveWindowFromZone)(HWND window, bool restoreSize) = 0;
/**
* @param id Zone identifier.
*/
@@ -45,7 +17,6 @@ interface __declspec(uuid("{8228E934-B6EF-402A-9892-15A1441BF8B0}")) IZone : pub
* @returns Zone identifier.
*/
IFACEMETHOD_(size_t, Id)() = 0;
/**
* Compute the coordinates of the rectangle to which a window should be resized.
*

View File

@@ -2,6 +2,7 @@
#include "util.h"
#include "lib/ZoneSet.h"
#include "Settings.h"
#include <common/dpi_aware.h>
@@ -123,8 +124,8 @@ public:
IFACEMETHODIMP AddZone(winrt::com_ptr<IZone> zone) noexcept;
IFACEMETHODIMP_(std::vector<int>)
ZonesFromPoint(POINT pt) noexcept;
IFACEMETHODIMP_(int)
GetZoneIndexFromWindow(HWND window) noexcept;
IFACEMETHODIMP_(std::vector<int>)
GetZoneIndexSetFromWindow(HWND window) noexcept;
IFACEMETHODIMP_(std::vector<winrt::com_ptr<IZone>>)
GetZones() noexcept { return m_zones; }
IFACEMETHODIMP_(void)
@@ -137,6 +138,8 @@ public:
MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept;
IFACEMETHODIMP_(bool)
CalculateZones(MONITORINFO monitorInfo, int zoneCount, int spacing) noexcept;
IFACEMETHODIMP_(bool)
IsZoneEmpty(int zoneIndex) noexcept;
private:
bool CalculateFocusLayout(Rect workArea, int zoneCount) noexcept;
@@ -144,12 +147,11 @@ private:
bool CalculateGridLayout(Rect workArea, JSONHelpers::ZoneSetLayoutType type, int zoneCount, int spacing) noexcept;
bool CalculateUniquePriorityGridLayout(Rect workArea, int zoneCount, int spacing) noexcept;
bool CalculateCustomLayout(Rect workArea, int spacing) noexcept;
bool CalculateGridZones(Rect workArea, JSONHelpers::GridLayoutInfo gridLayoutInfo, int spacing);
winrt::com_ptr<IZone> ZoneFromWindow(HWND window) noexcept;
void StampWindow(HWND window, size_t bitmask) noexcept;
std::vector<winrt::com_ptr<IZone>> m_zones;
std::map<HWND, std::vector<int>> m_windowIndexSet;
ZoneSetConfig m_config;
};
@@ -238,45 +240,23 @@ ZoneSet::ZonesFromPoint(POINT pt) noexcept
return capturedZones;
}
IFACEMETHODIMP_(int)
ZoneSet::GetZoneIndexFromWindow(HWND window) noexcept
std::vector<int> ZoneSet::GetZoneIndexSetFromWindow(HWND window) noexcept
{
int zoneIndex = 0;
for (auto iter = m_zones.begin(); iter != m_zones.end(); iter++, zoneIndex++)
auto it = m_windowIndexSet.find(window);
if (it == m_windowIndexSet.end())
{
if (winrt::com_ptr<IZone> zone = iter->try_as<IZone>())
{
if (zone->ContainsWindow(window))
{
return zoneIndex;
}
}
return {};
}
else
{
return it->second;
}
return -1;
}
IFACEMETHODIMP_(void)
ZoneSet::MoveWindowIntoZoneByIndex(HWND window, HWND windowZone, int index, bool stampZone) noexcept
{
if (m_zones.empty())
{
return;
}
if (index >= int(m_zones.size()))
{
return;
}
while (auto zoneDrop = ZoneFromWindow(window))
{
zoneDrop->RemoveWindowFromZone(window, !IsZoomed(window));
}
if (auto zone = m_zones.at(index))
{
zone->AddWindowToZone(window, windowZone, stampZone);
}
MoveWindowIntoZoneByIndexSet(window, windowZone, { index }, stampZone);
}
IFACEMETHODIMP_(void)
@@ -287,19 +267,12 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND windowZone, const std::v
return;
}
while (auto zoneDrop = ZoneFromWindow(window))
{
zoneDrop->RemoveWindowFromZone(window, !IsZoomed(window));
}
if (indexSet.size() == 1)
{
MoveWindowIntoZoneByIndex(window, windowZone, indexSet[0], stampZone);
return;
}
RECT size;
bool sizeEmpty = true;
size_t bitmask = 0;
auto& storedIndexSet = m_windowIndexSet[window];
storedIndexSet = {};
for (int index : indexSet)
{
@@ -318,12 +291,23 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND windowZone, const std::v
size = newSize;
sizeEmpty = false;
}
storedIndexSet.push_back(index);
}
if (index < std::numeric_limits<size_t>::digits)
{
bitmask |= 1ull << index;
}
}
if (!sizeEmpty)
{
SizeWindowToRect(window, size);
if (stampZone)
{
StampWindow(window, bitmask);
}
}
}
@@ -335,64 +319,48 @@ ZoneSet::MoveWindowIntoZoneByDirection(HWND window, HWND windowZone, DWORD vkCod
return false;
}
winrt::com_ptr<IZone> oldZone = nullptr;
winrt::com_ptr<IZone> newZone = nullptr;
auto indexSet = GetZoneIndexSetFromWindow(window);
int numZones = static_cast<int>(m_zones.size());
auto iter = std::find(m_zones.begin(), m_zones.end(), ZoneFromWindow(window));
if (iter == m_zones.end())
// The window was not assigned to any zone here
if (indexSet.size() == 0)
{
iter = (vkCode == VK_RIGHT) ? m_zones.begin() : m_zones.end() - 1;
}
else if (oldZone = iter->as<IZone>())
{
if (vkCode == VK_LEFT)
{
if (iter == m_zones.begin())
{
if (!cycle)
{
oldZone->RemoveWindowFromZone(window, false);
return false;
}
iter = m_zones.end();
}
iter--;
}
else if (vkCode == VK_RIGHT)
{
iter++;
if (iter == m_zones.end())
{
if (!cycle)
{
oldZone->RemoveWindowFromZone(window, false);
return false;
}
iter = m_zones.begin();
}
}
}
if (newZone = iter->as<IZone>())
{
if (oldZone)
{
oldZone->RemoveWindowFromZone(window, false);
}
newZone->AddWindowToZone(window, windowZone, true);
MoveWindowIntoZoneByIndexSet(window, windowZone, { vkCode == VK_LEFT ? numZones - 1 : 0 }, true);
return true;
}
return false;
int oldIndex = indexSet[0];
// We reached the edge
if ((vkCode == VK_LEFT && oldIndex == 0) || (vkCode == VK_RIGHT && oldIndex == numZones - 1))
{
if (!cycle)
{
MoveWindowIntoZoneByIndexSet(window, windowZone, {}, true);
return false;
}
else
{
MoveWindowIntoZoneByIndexSet(window, windowZone, { vkCode == VK_LEFT ? numZones - 1 : 0 }, true);
return true;
}
}
// We didn't reach the edge
if (vkCode == VK_LEFT)
{
MoveWindowIntoZoneByIndexSet(window, windowZone, { oldIndex - 1 }, true);
}
else
{
MoveWindowIntoZoneByIndexSet(window, windowZone, { oldIndex + 1 }, true);
}
return true;
}
IFACEMETHODIMP_(void)
ZoneSet::MoveWindowIntoZoneByPoint(HWND window, HWND zoneWindow, POINT ptClient) noexcept
{
while (auto zoneDrop = ZoneFromWindow(window))
{
zoneDrop->RemoveWindowFromZone(window, !IsZoomed(window));
}
auto zones = ZonesFromPoint(ptClient);
MoveWindowIntoZoneByIndexSet(window, zoneWindow, zones, true);
}
@@ -435,6 +403,19 @@ ZoneSet::CalculateZones(MONITORINFO monitorInfo, int zoneCount, int spacing) noe
return success;
}
bool ZoneSet::IsZoneEmpty(int zoneIndex) noexcept
{
for (auto& [window, zones] : m_windowIndexSet)
{
if (find(begin(zones), end(zones), zoneIndex) != end(zones))
{
return false;
}
}
return true;
}
bool ZoneSet::CalculateFocusLayout(Rect workArea, int zoneCount) noexcept
{
bool success = true;
@@ -713,19 +694,9 @@ bool ZoneSet::CalculateGridZones(Rect workArea, JSONHelpers::GridLayoutInfo grid
return success;
}
winrt::com_ptr<IZone> ZoneSet::ZoneFromWindow(HWND window) noexcept
void ZoneSet::StampWindow(HWND window, size_t bitmask) noexcept
{
for (auto iter = m_zones.begin(); iter != m_zones.end(); iter++)
{
if (winrt::com_ptr<IZone> zone = iter->try_as<IZone>())
{
if (zone->ContainsWindow(window))
{
return zone;
}
}
}
return nullptr;
SetProp(window, MULTI_ZONE_STAMP, reinterpret_cast<HANDLE>(bitmask));
}
winrt::com_ptr<IZoneSet> MakeZoneSet(ZoneSetConfig const& config) noexcept

View File

@@ -31,12 +31,12 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
*/
IFACEMETHOD_(std::vector<int>, ZonesFromPoint)(POINT pt) = 0;
/**
* Get index of the zone inside zone layout by window assigned to it.
* Get index set of the zones to which the window was assigned.
*
* @param window Handle of window assigned to zone.
* @returns Zone index withing zone layout.
* @param window Handle of the window.
* @returns A vector of integers, 0-based, the index set.
*/
IFACEMETHOD_(int, GetZoneIndexFromWindow)(HWND window) = 0;
IFACEMETHOD_(std::vector<int>, GetZoneIndexSetFromWindow)(HWND window) = 0;
/**
* @returns Array of zone objects (defining coordinates of the zone) inside this zone layout.
*/
@@ -95,6 +95,14 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
* @returns Boolean indicating if calculation was successful.
*/
IFACEMETHOD_(bool, CalculateZones)(MONITORINFO monitorInfo, int zoneCount, int spacing) = 0;
/**
* Check if the zone with the specified index is empty. Returns true if the zone does not exist.
*
* @param zoneIndex The index of of the zone within this zone set.
*
* @returns Boolean indicating whether the zone is empty.
*/
IFACEMETHOD_(bool, IsZoneEmpty)(int zoneIndex) = 0;
};
#define VERSION_PERSISTEDDATA 0x0000F00D

View File

@@ -484,13 +484,13 @@ ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
{
if (m_activeZoneSet)
{
DWORD zoneIndex = static_cast<DWORD>(m_activeZoneSet->GetZoneIndexFromWindow(window));
if (zoneIndex != -1)
auto zoneIndexSet = m_activeZoneSet->GetZoneIndexSetFromWindow(window);
if (zoneIndexSet.size())
{
OLECHAR* guidString;
if (StringFromCLSID(m_activeZoneSet->Id(), &guidString) == S_OK)
{
JSONHelpers::FancyZonesDataInstance().SetAppLastZone(window, m_uniqueId, guidString, zoneIndex);
JSONHelpers::FancyZonesDataInstance().SetAppLastZones(window, m_uniqueId, guidString, zoneIndexSet);
}
CoTaskMemFree(guidString);

View File

@@ -24,10 +24,14 @@ ZoneSetInfo GetZoneSetInfo(_In_opt_ winrt::com_ptr<IZoneSet> set) noexcept
{
auto zones = set->GetZones();
info.NumberOfZones = zones.size();
info.NumberOfWindows = std::count_if(zones.cbegin(), zones.cend(), [&](winrt::com_ptr<IZone> zone)
info.NumberOfWindows = 0;
for (int i = 0; i < static_cast<int>(zones.size()); i++)
{
return !zone->IsEmpty();
});
if (!set->IsZoneEmpty(i))
{
info.NumberOfWindows++;
}
}
}
return info;
}