mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 19:26:39 +02:00
[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:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user