diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index 6130f92526..457aa7dc28 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -419,7 +419,7 @@ void FancyZones::WindowCreated(HWND window) noexcept return; } - const bool isZoned = reinterpret_cast(::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) { diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp index 8ed426e880..096f824d94 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesData/AppZoneHistory.cpp @@ -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(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)); + auto windowZoneStamps = FancyZonesWindowProperties::RetrieveZoneIndexProperty(window); for (auto placedWindow : data->processIdToHandleMap) { - ZoneIndex placedWindowZoneStamp = reinterpret_cast(::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; } diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj index ae2969ca78..516c965c82 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj @@ -67,6 +67,7 @@ + @@ -90,6 +91,7 @@ ../pch.h ../pch.h + diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters index f36e8e5336..11c8ced847 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters @@ -114,6 +114,9 @@ Header Files + + Header Files + @@ -188,6 +191,9 @@ Source Files + + Source Files + diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProperties.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProperties.cpp new file mode 100644 index 0000000000..5a46397975 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProperties.cpp @@ -0,0 +1,109 @@ +#include "pch.h" +#include "FancyZonesWindowProperties.h" + +#include + +#include +#include + +// 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 data{ + static_cast(bitmask.part1), + static_cast(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 data{ + static_cast(bitmask.part2), + static_cast(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 data; + memcpy(data.data(), &handle64, sizeof data); + bitmask.part1 = (static_cast(data[1]) << 32) + data[0]; + } + + if (handle128) + { + std::array data; + memcpy(data.data(), &handle128, sizeof data); + bitmask.part2 = (static_cast(data[1]) << 32) + data[0]; + } + + return bitmask.ToIndexSet(); +} + +std::optional FancyZonesWindowProperties::GetTabSortKeyWithinZone(HWND window) +{ + auto rawTabSortKeyWithinZone = ::GetPropW(window, ZonedWindowProperties::PropertySortKeyWithinZone); + if (rawTabSortKeyWithinZone == NULL) + { + return std::nullopt; + } + + auto tabSortKeyWithinZone = reinterpret_cast(rawTabSortKeyWithinZone) - 1; + return tabSortKeyWithinZone; +} + +void FancyZonesWindowProperties::SetTabSortKeyWithinZone(HWND window, std::optional tabSortKeyWithinZone) +{ + if (!tabSortKeyWithinZone.has_value()) + { + ::RemovePropW(window, ZonedWindowProperties::PropertySortKeyWithinZone); + } + else + { + auto rawTabSortKeyWithinZone = reinterpret_cast(tabSortKeyWithinZone.value() + 1); + ::SetPropW(window, ZonedWindowProperties::PropertySortKeyWithinZone, rawTabSortKeyWithinZone); + } +} diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProperties.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProperties.h index 39942359db..f28f5e93a7 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProperties.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProperties.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -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 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::digits; i++) - { - if ((1ull << i) & bitmask) - { - zoneIndexSet.push_back(i); - } - } - } - - return zoneIndexSet; + std::optional GetTabSortKeyWithinZone(HWND window); + void SetTabSortKeyWithinZone(HWND window, std::optional tabSortKeyWithinZone); } -inline void StampWindow(HWND window, Bitmask bitmask) noexcept -{ - std::array data = { static_cast(bitmask), (bitmask >> 32) }; - HANDLE rawData; - memcpy(&rawData, data.data(), sizeof data); - SetProp(window, ZonedWindowProperties::PropertyMultipleZoneID, rawData); -} - -inline std::optional GetTabSortKeyWithinZone(HWND window) -{ - auto rawTabSortKeyWithinZone = ::GetPropW(window, ZonedWindowProperties::PropertySortKeyWithinZone); - if (rawTabSortKeyWithinZone == NULL) - { - return std::nullopt; - } - - auto tabSortKeyWithinZone = reinterpret_cast(rawTabSortKeyWithinZone) - 1; - return tabSortKeyWithinZone; -} - -inline void SetTabSortKeyWithinZone(HWND window, std::optional tabSortKeyWithinZone) -{ - if (!tabSortKeyWithinZone.has_value()) - { - ::RemovePropW(window, ZonedWindowProperties::PropertySortKeyWithinZone); - } - else - { - auto rawTabSortKeyWithinZone = reinterpret_cast(tabSortKeyWithinZone.value() + 1); - ::SetPropW(window, ZonedWindowProperties::PropertySortKeyWithinZone, rawTabSortKeyWithinZone); - } -} \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp b/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp index 3b2e4b565b..dab2e1b3e6 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WindowMoveHandler.cpp @@ -266,7 +266,8 @@ void WindowMoveHandler::MoveSizeEnd(HWND window, POINT const& ptScreen, const st } } } - ::RemoveProp(window, ZonedWindowProperties::PropertyMultipleZoneID); + + FancyZonesWindowProperties::RemoveZoneIndexProperty(window); } m_inDragging = false; diff --git a/src/modules/fancyzones/FancyZonesLib/Zone.h b/src/modules/fancyzones/FancyZonesLib/Zone.h index d45dbd2bdc..be1081610c 100644 --- a/src/modules/fancyzones/FancyZonesLib/Zone.h +++ b/src/modules/fancyzones/FancyZonesLib/Zone.h @@ -7,7 +7,6 @@ namespace ZoneConstants using ZoneIndex = int64_t; using ZoneIndexSet = std::vector; -using Bitmask = ZoneIndex; /** * Class representing one zone inside applied zone layout, which is basically wrapper around rectangle structure. diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneIndexSetBitmask.h b/src/modules/fancyzones/FancyZonesLib/ZoneIndexSetBitmask.h new file mode 100644 index 0000000000..14c7216927 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/ZoneIndexSetBitmask.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +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::digits) + { + bitmask.part1 |= 1ull << zoneIndex; + } + else + { + ZoneIndex index = zoneIndex - std::numeric_limits::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::digits; i++) + { + if ((1ull << i) & part1) + { + zoneIndexSet.push_back(i); + } + } + } + + if (part2 != 0) + { + for (ZoneIndex i = 0; i <= std::numeric_limits::digits; i++) + { + if ((1ull << i) & part2) + { + zoneIndexSet.push_back(i + std::numeric_limits::digits + 1); + } + } + } + + return zoneIndexSet; + } +}; \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp b/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp index 6357e6a629..4d16d9ee5a 100644 --- a/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp +++ b/src/modules/fancyzones/FancyZonesLib/ZoneSet.cpp @@ -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::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 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 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 tabSortKeyWit m_windowsByIndexSets[indexSet].push_back(window); } - SetTabSortKeyWithinZone(window, tabSortKeyWithinZone); + FancyZonesWindowProperties::SetTabSortKeyWithinZone(window, tabSortKeyWithinZone); } IFACEMETHODIMP_(bool) diff --git a/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp b/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp index f30895e611..cf22fe65f9 100644 --- a/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp +++ b/src/modules/fancyzones/FancyZonesTests/UnitTests/ZoneSet.Spec.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include #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(1), bitmask.part1); + Assert::AreEqual(static_cast(1), bitmask.part2); + } + + TEST_METHOD(BitmaskToIndexSet) + { + // prepare + ZoneIndexSetBitmask bitmask{ + .part1 = 1, + .part2 = 1, + }; + + // test + ZoneIndexSet set = bitmask.ToIndexSet(); + Assert::AreEqual(static_cast(2), set.size()); + Assert::AreEqual(static_cast(0), set[0]); + Assert::AreEqual(static_cast(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]); + } + } + }; } diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml b/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml index 8befc3e875..c23f4f2d11 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml +++ b/src/modules/fancyzones/editor/FancyZonesEditor/MainWindow.xaml @@ -513,7 +513,7 @@ Text="" />