[FancyZones] Increase the number of zones limit to 128 (#15976)

This commit is contained in:
Seraphima Zykova
2022-02-04 18:09:11 +03:00
committed by GitHub
parent f62dd6933c
commit a3dbb55404
13 changed files with 263 additions and 75 deletions

View File

@@ -419,7 +419,7 @@ void FancyZones::WindowCreated(HWND window) noexcept
return;
}
const bool isZoned = reinterpret_cast<ZoneIndex>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)) != 0;
const bool isZoned = !FancyZonesWindowProperties::RetrieveZoneIndexProperty(window).empty();
if (isZoned)
{
return;
@@ -957,7 +957,7 @@ void FancyZones::UpdateWindowsPositions(bool suppressMove) noexcept
{
for (const auto [window, desktopId] : m_virtualDesktop.GetWindowsRelatedToDesktops())
{
auto zoneIndexSet = GetZoneIndexSet(window);
auto zoneIndexSet = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
auto workArea = m_workAreaHandler.GetWorkArea(window, desktopId);
if (workArea)
{

View File

@@ -164,11 +164,11 @@ bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::D
}
// if there is another instance of same application placed in the same zone don't erase history
ZoneIndex windowZoneStamp = reinterpret_cast<ZoneIndex>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID));
auto windowZoneStamps = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window);
for (auto placedWindow : data->processIdToHandleMap)
{
ZoneIndex placedWindowZoneStamp = reinterpret_cast<ZoneIndex>(::GetProp(placedWindow.second, ZonedWindowProperties::PropertyMultipleZoneID));
if (IsWindow(placedWindow.second) && (windowZoneStamp == placedWindowZoneStamp))
auto placedWindowZoneStamps = FancyZonesWindowProperties::RetrieveZoneIndexProperty(placedWindow.second);
if (IsWindow(placedWindow.second) && (windowZoneStamps == placedWindowZoneStamps))
{
return false;
}

View File

@@ -67,6 +67,7 @@
<ClInclude Include="FancyZonesWindowProperties.h" />
<ClInclude Include="Zone.h" />
<ClInclude Include="ZoneColors.h" />
<ClInclude Include="ZoneIndexSetBitmask.h" />
<ClInclude Include="ZoneSet.h" />
<ClInclude Include="WorkArea.h" />
<ClInclude Include="ZonesOverlay.h" />
@@ -90,6 +91,7 @@
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="FancyZonesWindowProperties.cpp" />
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
<ClCompile Include="FancyZonesData.cpp" />
<ClCompile Include="JsonHelpers.cpp" />

View File

@@ -114,6 +114,9 @@
<ClInclude Include="FancyZonesData\Layout.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ZoneIndexSetBitmask.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@@ -188,6 +191,9 @@
<ClCompile Include="FancyZonesData\LayoutTemplates.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FancyZonesWindowProperties.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -0,0 +1,109 @@
#include "pch.h"
#include "FancyZonesWindowProperties.h"
#include <FancyZonesLib/ZoneIndexSetBitmask.h>
#include <common/logger/logger.h>
#include <common/utils/winapi_error.h>
// Zoned window properties are not localized.
namespace ZonedWindowProperties
{
const wchar_t PropertyMultipleZone64ID[] = L"FancyZones_zones"; // maximum possible zone count = 64
const wchar_t PropertyMultipleZone128ID[] = L"FancyZones_zones_max128"; // additional property to allow maximum possible zone count = 128
const wchar_t PropertySortKeyWithinZone[] = L"FancyZones_TabSortKeyWithinZone";
}
void FancyZonesWindowProperties::StampZoneIndexProperty(HWND window, const ZoneIndexSet& zoneSet)
{
RemoveZoneIndexProperty(window);
ZoneIndexSetBitmask bitmask = ZoneIndexSetBitmask::FromIndexSet(zoneSet);
if (bitmask.part1 != 0)
{
std::array<int32_t, 2> data{
static_cast<int>(bitmask.part1),
static_cast<int>(bitmask.part1 >> 32)
};
HANDLE rawData;
memcpy(&rawData, data.data(), sizeof data);
if (!SetProp(window, ZonedWindowProperties::PropertyMultipleZone64ID, rawData))
{
Logger::error(L"Failed to stamp window {}", get_last_error_or_default(GetLastError()));
}
}
if (bitmask.part2 != 0)
{
std::array<int32_t, 2> data{
static_cast<int>(bitmask.part2),
static_cast<int>(bitmask.part2 >> 32)
};
HANDLE rawData;
memcpy(&rawData, data.data(), sizeof data);
if (!SetProp(window, ZonedWindowProperties::PropertyMultipleZone128ID, rawData))
{
Logger::error(L"Failed to stamp window {}", get_last_error_or_default(GetLastError()));
}
}
}
void FancyZonesWindowProperties::RemoveZoneIndexProperty(HWND window)
{
::RemoveProp(window, ZonedWindowProperties::PropertyMultipleZone64ID);
::RemoveProp(window, ZonedWindowProperties::PropertyMultipleZone128ID);
}
ZoneIndexSet FancyZonesWindowProperties::RetrieveZoneIndexProperty(HWND window)
{
HANDLE handle64 = ::GetProp(window, ZonedWindowProperties::PropertyMultipleZone64ID);
HANDLE handle128 = ::GetProp(window, ZonedWindowProperties::PropertyMultipleZone128ID);
ZoneIndexSetBitmask bitmask{};
if (handle64)
{
std::array<int32_t, 2> data;
memcpy(data.data(), &handle64, sizeof data);
bitmask.part1 = (static_cast<decltype(bitmask.part1)>(data[1]) << 32) + data[0];
}
if (handle128)
{
std::array<int32_t, 2> data;
memcpy(data.data(), &handle128, sizeof data);
bitmask.part2 = (static_cast<decltype(bitmask.part2)>(data[1]) << 32) + data[0];
}
return bitmask.ToIndexSet();
}
std::optional<size_t> FancyZonesWindowProperties::GetTabSortKeyWithinZone(HWND window)
{
auto rawTabSortKeyWithinZone = ::GetPropW(window, ZonedWindowProperties::PropertySortKeyWithinZone);
if (rawTabSortKeyWithinZone == NULL)
{
return std::nullopt;
}
auto tabSortKeyWithinZone = reinterpret_cast<uint64_t>(rawTabSortKeyWithinZone) - 1;
return tabSortKeyWithinZone;
}
void FancyZonesWindowProperties::SetTabSortKeyWithinZone(HWND window, std::optional<size_t> tabSortKeyWithinZone)
{
if (!tabSortKeyWithinZone.has_value())
{
::RemovePropW(window, ZonedWindowProperties::PropertySortKeyWithinZone);
}
else
{
auto rawTabSortKeyWithinZone = reinterpret_cast<HANDLE>(tabSortKeyWithinZone.value() + 1);
::SetPropW(window, ZonedWindowProperties::PropertySortKeyWithinZone, rawTabSortKeyWithinZone);
}
}

View File

@@ -1,6 +1,5 @@
#pragma once
#include <vector>
#include <optional>
#include <FancyZonesLib/Zone.h>
@@ -8,66 +7,19 @@
// Zoned window properties are not localized.
namespace ZonedWindowProperties
{
const wchar_t PropertyMultipleZoneID[] = L"FancyZones_zones";
const wchar_t PropertySortKeyWithinZone[] = L"FancyZones_TabSortKeyWithinZone";
const wchar_t PropertyRestoreSizeID[] = L"FancyZones_RestoreSize";
const wchar_t PropertyRestoreOriginID[] = L"FancyZones_RestoreOrigin";
const wchar_t MultiMonitorDeviceID[] = L"FancyZones#MultiMonitorDevice";
}
inline ZoneIndexSet GetZoneIndexSet(HWND window)
namespace FancyZonesWindowProperties
{
HANDLE handle = ::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID);
ZoneIndexSet zoneIndexSet;
void StampZoneIndexProperty(HWND window, const ZoneIndexSet& zoneSet);
void RemoveZoneIndexProperty(HWND window);
ZoneIndexSet RetrieveZoneIndexProperty(HWND window);
std::array<int, 2> data;
memcpy(data.data(), &handle, sizeof data);
uint64_t bitmask = ((uint64_t)data[1] << 32) + data[0];
if (bitmask != 0)
{
for (int i = 0; i < std::numeric_limits<ZoneIndex>::digits; i++)
{
if ((1ull << i) & bitmask)
{
zoneIndexSet.push_back(i);
}
}
}
return zoneIndexSet;
std::optional<size_t> GetTabSortKeyWithinZone(HWND window);
void SetTabSortKeyWithinZone(HWND window, std::optional<size_t> tabSortKeyWithinZone);
}
inline void StampWindow(HWND window, Bitmask bitmask) noexcept
{
std::array<int, 2> data = { static_cast<int>(bitmask), (bitmask >> 32) };
HANDLE rawData;
memcpy(&rawData, data.data(), sizeof data);
SetProp(window, ZonedWindowProperties::PropertyMultipleZoneID, rawData);
}
inline std::optional<size_t> GetTabSortKeyWithinZone(HWND window)
{
auto rawTabSortKeyWithinZone = ::GetPropW(window, ZonedWindowProperties::PropertySortKeyWithinZone);
if (rawTabSortKeyWithinZone == NULL)
{
return std::nullopt;
}
auto tabSortKeyWithinZone = reinterpret_cast<uint64_t>(rawTabSortKeyWithinZone) - 1;
return tabSortKeyWithinZone;
}
inline void SetTabSortKeyWithinZone(HWND window, std::optional<size_t> tabSortKeyWithinZone)
{
if (!tabSortKeyWithinZone.has_value())
{
::RemovePropW(window, ZonedWindowProperties::PropertySortKeyWithinZone);
}
else
{
auto rawTabSortKeyWithinZone = reinterpret_cast<HANDLE>(tabSortKeyWithinZone.value() + 1);
::SetPropW(window, ZonedWindowProperties::PropertySortKeyWithinZone, rawTabSortKeyWithinZone);
}
}

View File

@@ -266,7 +266,8 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st
}
}
}
::RemoveProp(window, ZonedWindowProperties::PropertyMultipleZoneID);
FancyZonesWindowProperties::RemoveZoneIndexProperty(window);
}
m_inDragging = false;

View File

@@ -7,7 +7,6 @@ namespace ZoneConstants
using ZoneIndex = int64_t;
using ZoneIndexSet = std::vector<ZoneIndex>;
using Bitmask = ZoneIndex;
/**
* Class representing one zone inside applied zone layout, which is basically wrapper around rectangle structure.

View File

@@ -0,0 +1,58 @@
#pragma once
#include <FancyZonesLib/Zone.h>
struct ZoneIndexSetBitmask
{
uint64_t part1{ 0 }; // represents 0-63 zones
uint64_t part2{ 0 }; // represents 64-127 zones
static ZoneIndexSetBitmask FromIndexSet(const ZoneIndexSet& set)
{
ZoneIndexSetBitmask bitmask{};
for (const auto zoneIndex : set)
{
if (zoneIndex <= std::numeric_limits<ZoneIndex>::digits)
{
bitmask.part1 |= 1ull << zoneIndex;
}
else
{
ZoneIndex index = zoneIndex - std::numeric_limits<ZoneIndex>::digits - 1;
bitmask.part2 |= 1ull << index;
}
}
return bitmask;
}
ZoneIndexSet ToIndexSet() const noexcept
{
ZoneIndexSet zoneIndexSet;
if (part1 != 0)
{
for (ZoneIndex i = 0; i <= std::numeric_limits<ZoneIndex>::digits; i++)
{
if ((1ull << i) & part1)
{
zoneIndexSet.push_back(i);
}
}
}
if (part2 != 0)
{
for (ZoneIndex i = 0; i <= std::numeric_limits<ZoneIndex>::digits; i++)
{
if ((1ull << i) & part2)
{
zoneIndexSet.push_back(i + std::numeric_limits<ZoneIndex>::digits + 1);
}
}
}
return zoneIndexSet;
}
};

View File

@@ -310,12 +310,11 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND workAreaWindow, const Zo
m_windowInitialIndexSet.erase(window);
}
auto tabSortKeyWithinZone = GetTabSortKeyWithinZone(window);
auto tabSortKeyWithinZone = FancyZonesWindowProperties::GetTabSortKeyWithinZone(window);
DismissWindow(window);
RECT size;
bool sizeEmpty = true;
Bitmask bitmask = 0;
auto& indexSet = m_windowIndexSet[window];
for (ZoneIndex id : zoneIds)
@@ -339,11 +338,6 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND workAreaWindow, const Zo
indexSet.push_back(id);
}
if (id < std::numeric_limits<ZoneIndex>::digits)
{
bitmask |= 1ull << id;
}
}
if (!sizeEmpty)
@@ -356,7 +350,7 @@ ZoneSet::MoveWindowIntoZoneByIndexSet(HWND window, HWND workAreaWindow, const Zo
SizeWindowToRect(window, rect);
}
StampWindow(window, bitmask);
FancyZonesWindowProperties::StampZoneIndexProperty(window, indexSet);
InsertTabIntoZone(window, tabSortKeyWithinZone, indexSet);
}
}
@@ -577,7 +571,7 @@ void ZoneSet::DismissWindow(HWND window) noexcept
indexSet.clear();
}
SetTabSortKeyWithinZone(window, std::nullopt);
FancyZonesWindowProperties::SetTabSortKeyWithinZone(window, std::nullopt);
}
IFACEMETHODIMP_(void)
@@ -630,7 +624,7 @@ void ZoneSet::InsertTabIntoZone(HWND window, std::optional<size_t> tabSortKeyWit
{
// Insert the tab using the provided sort key
auto predicate = [tabSortKeyWithinZone](HWND tab) {
auto currentTabSortKeyWithinZone = GetTabSortKeyWithinZone(tab);
auto currentTabSortKeyWithinZone = FancyZonesWindowProperties::GetTabSortKeyWithinZone(tab);
if (currentTabSortKeyWithinZone.has_value())
{
return currentTabSortKeyWithinZone.value() > tabSortKeyWithinZone;
@@ -651,7 +645,7 @@ void ZoneSet::InsertTabIntoZone(HWND window, std::optional<size_t> tabSortKeyWit
if (!m_windowsByIndexSets[indexSet].empty())
{
auto prevTab = m_windowsByIndexSets[indexSet].back();
auto prevTabSortKeyWithinZone = GetTabSortKeyWithinZone(prevTab);
auto prevTabSortKeyWithinZone = FancyZonesWindowProperties::GetTabSortKeyWithinZone(prevTab);
if (prevTabSortKeyWithinZone.has_value())
{
tabSortKeyWithinZone = prevTabSortKeyWithinZone.value() + 1;
@@ -661,7 +655,7 @@ void ZoneSet::InsertTabIntoZone(HWND window, std::optional<size_t> tabSortKeyWit
m_windowsByIndexSets[indexSet].push_back(window);
}
SetTabSortKeyWithinZone(window, tabSortKeyWithinZone);
FancyZonesWindowProperties::SetTabSortKeyWithinZone(window, tabSortKeyWithinZone);
}
IFACEMETHODIMP_(bool)

View File

@@ -1,6 +1,7 @@
#include "pch.h"
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
#include "FancyZonesLib\FancyZonesDataTypes.h"
#include "FancyZonesLib\ZoneIndexSetBitmask.h"
#include "FancyZonesLib\JsonHelpers.h"
#include "FancyZonesLib\VirtualDesktop.h"
#include "FancyZonesLib\ZoneSet.h"
@@ -1066,4 +1067,70 @@ namespace FancyZonesUnitTests
}
}
};
TEST_CLASS(ZoneIndexSetUnitTests)
{
TEST_METHOD (BitmaskFromIndexSetTest)
{
// prepare
ZoneIndexSet set {0, 64};
// test
ZoneIndexSetBitmask bitmask = ZoneIndexSetBitmask::FromIndexSet(set);
Assert::AreEqual(static_cast<uint64_t>(1), bitmask.part1);
Assert::AreEqual(static_cast<uint64_t>(1), bitmask.part2);
}
TEST_METHOD(BitmaskToIndexSet)
{
// prepare
ZoneIndexSetBitmask bitmask{
.part1 = 1,
.part2 = 1,
};
// test
ZoneIndexSet set = bitmask.ToIndexSet();
Assert::AreEqual(static_cast<size_t>(2), set.size());
Assert::AreEqual(static_cast<ZoneIndex>(0), set[0]);
Assert::AreEqual(static_cast<ZoneIndex>(64), set[1]);
}
TEST_METHOD (BitmaskConvertTest)
{
// prepare
ZoneIndexSet set{ 53, 54, 55, 65, 66, 67 };
ZoneIndexSetBitmask bitmask = ZoneIndexSetBitmask::FromIndexSet(set);
// test
ZoneIndexSet actual = bitmask.ToIndexSet();
Assert::AreEqual(set.size(), actual.size());
for (int i = 0; i < set.size(); i++)
{
Assert::AreEqual(set[i], actual[i]);
}
}
TEST_METHOD (BitmaskConvert2Test)
{
// prepare
ZoneIndexSet set;
for (int i = 0; i < 128; i++)
{
set.push_back(i);
}
ZoneIndexSetBitmask bitmask = ZoneIndexSetBitmask::FromIndexSet(set);
// test
ZoneIndexSet actual = bitmask.ToIndexSet();
Assert::AreEqual(set.size(), actual.size());
for (int i = 0; i < set.size(); i++)
{
Assert::AreEqual(set[i], actual[i]);
}
}
};
}

View File

@@ -513,7 +513,7 @@
Text="&#xECA5;" />
<ui:NumberBox Minimum="1"
Maximum="40"
Maximum="128"
Width="216"
KeyDown="EditDialogNumberBox_KeyDown"
Margin="12,0,0,0"

View File

@@ -18,7 +18,7 @@ namespace FancyZonesEditor
public const int DefaultSensitivityRadius = 20;
public const int MaxZones = 40;
public const int MaxZones = 128;
public string ZonesetUuid { get; set; } = string.Empty;