[FancyZones] Split zones-settings: devices -> applied layouts (#15779)

This commit is contained in:
Seraphima Zykova
2022-01-27 15:21:15 +03:00
committed by GitHub
parent 792a04cf48
commit 03c36b4f65
41 changed files with 1461 additions and 1362 deletions

View File

@@ -12,9 +12,11 @@
#include <common/SettingsAPI/FileWatcher.h>
#include <FancyZonesLib/FancyZonesData.h>
#include <FancyZonesLib/FancyZonesData/AppliedLayouts.h>
#include <FancyZonesLib/FancyZonesData/AppZoneHistory.h>
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
#include <FancyZonesLib/FancyZonesData/LayoutHotkeys.h>
#include <FancyZonesLib/FancyZonesData/LayoutTemplates.h>
#include <FancyZonesLib/FancyZonesWindowProperties.h>
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
#include <FancyZonesLib/MonitorUtils.h>
@@ -57,9 +59,6 @@ public:
m_windowMoveHandler(settings, [this]() {
PostMessageW(m_window, WM_PRIV_LOCATIONCHANGE, NULL, NULL);
}),
m_zonesSettingsFileWatcher(FancyZonesDataInstance().GetZonesSettingsFileName(), [this]() {
PostMessageW(m_window, WM_PRIV_FILE_UPDATE, NULL, NULL);
}),
m_settingsFileWatcher(FancyZonesDataInstance().GetSettingsFileName(), [this]() {
PostMessageW(m_window, WM_PRIV_SETTINGS_CHANGED, NULL, NULL);
}),
@@ -73,8 +72,10 @@ public:
this->disableModuleCallback = std::move(disableModuleCallback);
FancyZonesDataInstance().ReplaceZoneSettingsFileFromOlderVersions();
LayoutHotkeys::instance().LoadData();
LayoutTemplates::instance().LoadData();
CustomLayouts::instance().LoadData();
LayoutHotkeys::instance().LoadData();
AppliedLayouts::instance().LoadData();
AppZoneHistory::instance().LoadData();
}
@@ -199,7 +200,6 @@ private:
MonitorWorkAreaHandler m_workAreaHandler;
VirtualDesktop m_virtualDesktop;
FileWatcher m_zonesSettingsFileWatcher;
FileWatcher m_settingsFileWatcher;
winrt::com_ptr<IFancyZonesSettings> m_settings{};
@@ -276,7 +276,7 @@ FancyZones::Run() noexcept
}
});
FancyZonesDataInstance().SetVirtualDesktopCheckCallback(std::bind(&VirtualDesktop::IsVirtualDesktopIdSavedInRegistry, &m_virtualDesktop, std::placeholders::_1));
AppliedLayouts::instance().SetVirtualDesktopCheckCallback(std::bind(&VirtualDesktop::IsVirtualDesktopIdSavedInRegistry, &m_virtualDesktop, std::placeholders::_1));
AppZoneHistory::instance().SetVirtualDesktopCheckCallback(std::bind(&VirtualDesktop::IsVirtualDesktopIdSavedInRegistry, &m_virtualDesktop, std::placeholders::_1));
}
@@ -336,7 +336,7 @@ std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> FancyZones::GetAppZoneHistory
void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IWorkArea> workArea, const ZoneIndexSet& zoneIndexSet) noexcept
{
_TRACER_;
auto& fancyZonesData = FancyZonesDataInstance();
if (!AppZoneHistory::instance().IsAnotherWindowOfApplicationInstanceZoned(window, workArea->UniqueId()))
{
if (workArea)
@@ -771,19 +771,23 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
auto hwnd = reinterpret_cast<HWND>(wparam);
WindowCreated(hwnd);
}
else if (message == WM_PRIV_FILE_UPDATE)
{
FancyZonesDataInstance().LoadFancyZonesData();
UpdateZoneSets();
}
else if (message == WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE)
{
LayoutHotkeys::instance().LoadData();
}
else if (message == WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE)
{
LayoutTemplates::instance().LoadData();
}
else if (message == WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE)
{
CustomLayouts::instance().LoadData();
}
else if (message == WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE)
{
AppliedLayouts::instance().LoadData();
UpdateZoneSets();
}
else if (message == WM_PRIV_QUICK_LAYOUT_KEY)
{
ApplyQuickLayout(static_cast<int>(lparam));
@@ -895,7 +899,7 @@ void FancyZones::AddWorkArea(HMONITOR monitor, const std::wstring& deviceId) noe
if (workArea)
{
m_workAreaHandler.AddWorkArea(m_currentDesktopId, monitor, workArea);
FancyZonesDataInstance().SaveZoneSettings();
AppliedLayouts::instance().SaveData();
}
}
}
@@ -1217,10 +1221,12 @@ void FancyZones::RegisterVirtualDesktopUpdates() noexcept
if (guids.has_value())
{
m_workAreaHandler.RegisterUpdates(*guids);
FancyZonesDataInstance().RemoveDeletedDesktops(*guids);
AppZoneHistory::instance().RemoveDeletedVirtualDesktops(*guids);
AppliedLayouts::instance().RemoveDeletedVirtualDesktops(*guids);
}
FancyZonesDataInstance().SyncVirtualDesktops(m_currentDesktopId);
AppZoneHistory::instance().SyncVirtualDesktops(m_currentDesktopId);
AppliedLayouts::instance().SyncVirtualDesktops(m_currentDesktopId);
}
void FancyZones::UpdateHotkey(int hotkeyId, const PowerToysSettings::HotkeyObject& hotkeyObject, bool enable) noexcept
@@ -1269,8 +1275,8 @@ void FancyZones::OnSettingsChanged() noexcept
void FancyZones::OnEditorExitEvent() noexcept
{
// Collect information about changes in zone layout after editor exited.
FancyZonesDataInstance().LoadFancyZonesData();
FancyZonesDataInstance().SyncVirtualDesktops(m_currentDesktopId);
AppZoneHistory::instance().SyncVirtualDesktops(m_currentDesktopId);
AppliedLayouts::instance().SyncVirtualDesktops(m_currentDesktopId);
UpdateZoneSets();
}
@@ -1332,8 +1338,8 @@ void FancyZones::ApplyQuickLayout(int key) noexcept
FancyZonesDataTypes::ZoneSetData data{ .uuid = uuidStr.value(), .type = FancyZonesDataTypes::ZoneSetLayoutType::Custom };
auto workArea = m_workAreaHandler.GetWorkAreaFromCursor(m_currentDesktopId);
FancyZonesDataInstance().SetActiveZoneSet(workArea->UniqueId(), data);
FancyZonesDataInstance().SaveZoneSettings();
AppliedLayouts::instance().ApplyLayout(workArea->UniqueId(), data);
AppliedLayouts::instance().SaveData();
UpdateZoneSets();
FlashZones();
}

View File

@@ -1,149 +1,23 @@
#include "pch.h"
#include "FancyZonesData.h"
#include "FancyZonesDataTypes.h"
#include "JsonHelpers.h"
#include "ZoneSet.h"
#include "Settings.h"
#include "GuidUtils.h"
#include <filesystem>
#include <common/Display/dpi_aware.h>
#include <common/logger/call_tracer.h>
#include <common/utils/json.h>
#include <FancyZonesLib/util.h>
#include <FancyZonesLib/FancyZonesWindowProperties.h>
#include <shlwapi.h>
#include <filesystem>
#include <fstream>
#include <optional>
#include <regex>
#include <sstream>
#include <unordered_set>
#include <common/utils/process_path.h>
#include <common/logger/logger.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <FancyZonesLib/FancyZonesData/AppZoneHistory.h>
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
#include <FancyZonesLib/FancyZonesData/LayoutHotkeys.h>
#include <FancyZonesLib/JsonHelpers.h>
#include <FancyZonesLib/ModuleConstants.h>
#include <FancyZonesLib/util.h>
// Non-localizable strings
namespace NonLocalizable
{
const wchar_t NullStr[] = L"null";
const wchar_t FancyZonesSettingsFile[] = L"settings.json";
const wchar_t FancyZonesDataFile[] = L"zones-settings.json";
const wchar_t FancyZonesAppZoneHistoryFile[] = L"app-zone-history.json";
const wchar_t FancyZonesEditorParametersFile[] = L"editor-parameters.json";
const wchar_t RegistryPath[] = L"Software\\SuperFancyZones";
}
namespace
{
std::wstring ExtractVirtualDesktopId(const std::wstring& deviceId)
{
// Format: <device-id>_<resolution>_<virtual-desktop-id>
return deviceId.substr(deviceId.rfind('_') + 1);
}
const std::wstring& GetTempDirPath()
{
static std::wstring tmpDirPath;
static std::once_flag flag;
std::call_once(flag, []() {
wchar_t buffer[MAX_PATH];
auto charsWritten = GetTempPath(MAX_PATH, buffer);
if (charsWritten > MAX_PATH || (charsWritten == 0))
{
abort();
}
tmpDirPath = std::wstring{ buffer };
});
return tmpDirPath;
}
bool DeleteRegistryKey(HKEY hKeyRoot, LPTSTR lpSubKey)
{
// First, see if we can delete the key without having to recurse.
if (ERROR_SUCCESS == RegDeleteKey(hKeyRoot, lpSubKey))
{
return true;
}
HKEY hKey;
if (ERROR_SUCCESS != RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey))
{
return false;
}
// Check for an ending slash and add one if it is missing.
LPTSTR lpEnd = lpSubKey + lstrlen(lpSubKey);
if (*(lpEnd - 1) != TEXT('\\'))
{
*lpEnd = TEXT('\\');
lpEnd++;
*lpEnd = TEXT('\0');
}
// Enumerate the keys
DWORD dwSize = MAX_PATH;
TCHAR szName[MAX_PATH];
FILETIME ftWrite;
auto result = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
if (result == ERROR_SUCCESS)
{
do
{
*lpEnd = TEXT('\0');
StringCchCat(lpSubKey, MAX_PATH * 2, szName);
if (!DeleteRegistryKey(hKeyRoot, lpSubKey))
{
break;
}
dwSize = MAX_PATH;
result = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
} while (result == ERROR_SUCCESS);
}
lpEnd--;
*lpEnd = TEXT('\0');
RegCloseKey(hKey);
// Try again to delete the root key.
if (ERROR_SUCCESS == RegDeleteKey(hKeyRoot, lpSubKey))
{
return true;
}
return false;
}
bool DeleteFancyZonesRegistryData()
{
wchar_t key[256];
StringCchPrintf(key, ARRAYSIZE(key), L"%s", NonLocalizable::RegistryPath);
HKEY hKey;
if (ERROR_FILE_NOT_FOUND == RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey))
{
return true;
}
else
{
return DeleteRegistryKey(HKEY_CURRENT_USER, key);
}
}
}
FancyZonesData& FancyZonesDataInstance()
@@ -157,8 +31,8 @@ FancyZonesData::FancyZonesData()
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
settingsFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesSettingsFile);
zonesSettingsFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesDataFile);
appZoneHistoryFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesAppZoneHistoryFile);
zonesSettingsFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesDataFile);
editorParametersFileName = saveFolderPath + L"\\" + std::wstring(NonLocalizable::FancyZonesEditorParametersFile);
}
@@ -166,9 +40,15 @@ void FancyZonesData::ReplaceZoneSettingsFileFromOlderVersions()
{
if (std::filesystem::exists(zonesSettingsFileName))
{
json::JsonObject fancyZonesDataJSON = GetPersistFancyZonesJSON();
Logger::info("Replace zones-settings file");
//deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
json::JsonObject fancyZonesDataJSON = JSONHelpers::GetPersistFancyZonesJSON(zonesSettingsFileName, appZoneHistoryFileName);
auto deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
if (deviceInfoMap)
{
JSONHelpers::SaveAppliedLayouts(deviceInfoMap.value());
}
auto customLayouts = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON);
if (customLayouts)
@@ -187,295 +67,8 @@ void FancyZonesData::ReplaceZoneSettingsFileFromOlderVersions()
{
JSONHelpers::SaveLayoutHotkeys(quickKeysMap.value());
}
}
//TODO: remove zone-settings.json after getting all info from it
}
void FancyZonesData::SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback)
{
m_virtualDesktopCheckCallback = callback;
}
const JSONHelpers::TDeviceInfoMap& FancyZonesData::GetDeviceInfoMap() const
{
std::scoped_lock lock{ dataLock };
return deviceInfoMap;
}
std::optional<FancyZonesDataTypes::DeviceInfoData> FancyZonesData::FindDeviceInfo(const FancyZonesDataTypes::DeviceIdData& id) const
{
std::scoped_lock lock{ dataLock };
for (const auto& [deviceId, deviceInfo] : deviceInfoMap)
{
if (id.isEqualWithNullVirtualDesktopId(deviceId))
{
return deviceInfo;
}
}
return std::nullopt;
}
bool FancyZonesData::AddDevice(const FancyZonesDataTypes::DeviceIdData& deviceId)
{
_TRACER_;
using namespace FancyZonesDataTypes;
auto deviceInfo = FindDeviceInfo(deviceId);
std::scoped_lock lock{ dataLock };
if (!deviceInfo.has_value())
{
wil::unique_cotaskmem_string virtualDesktopId;
if (SUCCEEDED(StringFromCLSID(deviceId.virtualDesktopId, &virtualDesktopId)))
{
Logger::info(L"Create new device on virtual desktop {}", virtualDesktopId.get());
}
// Creates default entry in map when WorkArea is created
GUID guid;
auto result{ CoCreateGuid(&guid) };
wil::unique_cotaskmem_string guidString;
if (result == S_OK && SUCCEEDED(StringFromCLSID(guid, &guidString)))
{
const ZoneSetData zoneSetData{ guidString.get(), ZoneSetLayoutType::PriorityGrid };
DeviceInfoData defaultDeviceInfoData{ zoneSetData, DefaultValues::ShowSpacing, DefaultValues::Spacing, DefaultValues::ZoneCount, DefaultValues::SensitivityRadius };
deviceInfoMap[deviceId] = std::move(defaultDeviceInfoData);
return true;
}
else
{
Logger::error("Failed to create an ID for the new layout");
}
}
return false;
}
void FancyZonesData::CloneDeviceInfo(const FancyZonesDataTypes::DeviceIdData& source, const FancyZonesDataTypes::DeviceIdData& destination)
{
if (source == destination)
{
return;
}
std::scoped_lock lock{ dataLock };
// The source virtual desktop is deleted, simply ignore it.
if (!FindDeviceInfo(source).has_value())
{
return;
}
deviceInfoMap[destination] = deviceInfoMap[source];
}
void FancyZonesData::SyncVirtualDesktops(GUID currentVirtualDesktopId)
{
_TRACER_;
// Explorer persists current virtual desktop identifier to registry on a per session basis,
// but only after first virtual desktop switch happens. If the user hasn't switched virtual
// desktops in this session value in registry will be empty and we will use default GUID in
// that case (00000000-0000-0000-0000-000000000000).
// This method will go through all our persisted data with default GUID and update it with
// valid one.
std::scoped_lock lock{ dataLock };
bool dirtyFlag = false;
for (auto& [path, perDesktopData] : appZoneHistoryMap)
{
for (auto& data : perDesktopData)
{
if (data.deviceId.virtualDesktopId == GUID_NULL)
{
data.deviceId.virtualDesktopId = currentVirtualDesktopId;
dirtyFlag = true;
}
else
{
if (m_virtualDesktopCheckCallback && !m_virtualDesktopCheckCallback(data.deviceId.virtualDesktopId))
{
data.deviceId.virtualDesktopId = GUID_NULL;
dirtyFlag = true;
}
}
}
}
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithCurrentId{};
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithNullId{};
for (const auto& [desktopId, data] : deviceInfoMap)
{
if (desktopId.virtualDesktopId == GUID_NULL)
{
replaceWithCurrentId.push_back(desktopId);
dirtyFlag = true;
}
else
{
if (m_virtualDesktopCheckCallback && !m_virtualDesktopCheckCallback(desktopId.virtualDesktopId))
{
replaceWithNullId.push_back(desktopId);
dirtyFlag = true;
}
}
}
for (const auto& id : replaceWithCurrentId)
{
auto mapEntry = deviceInfoMap.extract(id);
mapEntry.key().virtualDesktopId = currentVirtualDesktopId;
deviceInfoMap.insert(std::move(mapEntry));
}
for (const auto& id : replaceWithNullId)
{
auto mapEntry = deviceInfoMap.extract(id);
mapEntry.key().virtualDesktopId = GUID_NULL;
deviceInfoMap.insert(std::move(mapEntry));
}
if (dirtyFlag)
{
wil::unique_cotaskmem_string virtualDesktopIdStr;
if (SUCCEEDED(StringFromCLSID(currentVirtualDesktopId, &virtualDesktopIdStr)))
{
Logger::info(L"Update Virtual Desktop id to {}", virtualDesktopIdStr.get());
}
SaveZoneSettings();
AppZoneHistory::instance().SaveData();
}
}
void FancyZonesData::RemoveDeletedDesktops(const std::vector<GUID>& activeDesktops)
{
std::unordered_set<GUID> active(std::begin(activeDesktops), std::end(activeDesktops));
std::scoped_lock lock{ dataLock };
bool dirtyFlag = false;
for (auto it = std::begin(deviceInfoMap); it != std::end(deviceInfoMap);)
{
GUID desktopId = it->first.virtualDesktopId;
if (desktopId != GUID_NULL)
{
auto foundId = active.find(desktopId);
if (foundId == std::end(active))
{
wil::unique_cotaskmem_string virtualDesktopIdStr;
if (SUCCEEDED(StringFromCLSID(desktopId, &virtualDesktopIdStr)))
{
Logger::info(L"Remove Virtual Desktop id {}", virtualDesktopIdStr.get());
}
AppZoneHistory::instance().RemoveDesktopAppZoneHistory(desktopId);
it = deviceInfoMap.erase(it);
dirtyFlag = true;
continue;
}
}
++it;
}
if (dirtyFlag)
{
SaveZoneSettings();
AppZoneHistory::instance().SaveData();
}
}
void FancyZonesData::SetActiveZoneSet(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& data)
{
std::scoped_lock lock{ dataLock };
for (auto& [deviceIdData, deviceInfo] : deviceInfoMap)
{
if (deviceId.isEqualWithNullVirtualDesktopId(deviceIdData))
{
deviceInfo.activeZoneSet = data;
// If the zone set is custom, we need to copy its properties to the device
auto id = FancyZonesUtils::GuidFromString(data.uuid);
if (id.has_value())
{
auto layout = CustomLayouts::instance().GetLayout(id.value());
if (layout)
{
if (layout.value().type == FancyZonesDataTypes::CustomLayoutType::Grid)
{
auto layoutInfo = std::get<FancyZonesDataTypes::GridLayoutInfo>(layout.value().info);
deviceInfo.sensitivityRadius = layoutInfo.sensitivityRadius();
deviceInfo.showSpacing = layoutInfo.showSpacing();
deviceInfo.spacing = layoutInfo.spacing();
deviceInfo.zoneCount = layoutInfo.zoneCount();
}
else if (layout.value().type == FancyZonesDataTypes::CustomLayoutType::Canvas)
{
auto layoutInfo = std::get<FancyZonesDataTypes::CanvasLayoutInfo>(layout.value().info);
deviceInfo.sensitivityRadius = layoutInfo.sensitivityRadius;
deviceInfo.zoneCount = (int)layoutInfo.zones.size();
}
}
}
break;
}
}
}
json::JsonObject FancyZonesData::GetPersistFancyZonesJSON()
{
return JSONHelpers::GetPersistFancyZonesJSON(zonesSettingsFileName, appZoneHistoryFileName);
}
void FancyZonesData::LoadFancyZonesData()
{
if (!std::filesystem::exists(zonesSettingsFileName))
{
SaveZoneSettings();
AppZoneHistory::instance().SaveData();
}
else
{
json::JsonObject fancyZonesDataJSON = GetPersistFancyZonesJSON();
deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
}
}
void FancyZonesData::SaveZoneSettings() const
{
_TRACER_;
std::scoped_lock lock{ dataLock };
bool dirtyFlag = false;
JSONHelpers::TDeviceInfoMap updatedDeviceInfoMap;
if (m_virtualDesktopCheckCallback)
{
for (const auto& [id, data] : deviceInfoMap)
{
auto updatedId = id;
if (!m_virtualDesktopCheckCallback(id.virtualDesktopId))
{
updatedId.virtualDesktopId = GUID_NULL;
dirtyFlag = true;
}
updatedDeviceInfoMap.insert({ updatedId, data });
}
}
if (dirtyFlag)
{
JSONHelpers::SaveZoneSettings(zonesSettingsFileName, updatedDeviceInfoMap);
}
else
{
JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap);
std::filesystem::remove(zonesSettingsFileName);
}
}

View File

@@ -1,38 +1,16 @@
#pragma once
#include "JsonHelpers.h"
#if defined(UNIT_TESTS)
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/json.h>
#include <mutex>
#include <string>
#include <unordered_map>
#include <optional>
#include <vector>
#include <winnt.h>
#include <FancyZonesLib/JsonHelpers.h>
namespace FancyZonesDataTypes
{
struct ZoneSetData;
struct DeviceIdData;
struct DeviceInfoData;
struct CustomLayoutData;
struct AppZoneHistoryData;
}
#endif
#if defined(UNIT_TESTS)
namespace FancyZonesUnitTests
{
class FancyZonesDataUnitTests;
class FancyZonesIFancyZonesCallbackUnitTests;
class ZoneSetCalculateZonesUnitTests;
class WorkAreaUnitTests;
class WorkAreaCreationUnitTests;
class LayoutHotkeysUnitTests;
class LayoutTemplatesUnitTests;
class CustomLayoutsUnitTests;
class AppliedLayoutsUnitTests;
}
#endif
@@ -43,63 +21,19 @@ public:
void ReplaceZoneSettingsFileFromOlderVersions();
void SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback);
std::optional<FancyZonesDataTypes::DeviceInfoData> FindDeviceInfo(const FancyZonesDataTypes::DeviceIdData& id) const;
const JSONHelpers::TDeviceInfoMap& GetDeviceInfoMap() const;
inline const std::wstring& GetZonesSettingsFileName() const
{
return zonesSettingsFileName;
}
inline const std::wstring& GetSettingsFileName() const
{
return settingsFileName;
}
bool AddDevice(const FancyZonesDataTypes::DeviceIdData& deviceId);
void CloneDeviceInfo(const FancyZonesDataTypes::DeviceIdData& source, const FancyZonesDataTypes::DeviceIdData& destination);
void SyncVirtualDesktops(GUID desktopId);
void RemoveDeletedDesktops(const std::vector<GUID>& activeDesktops);
void SetActiveZoneSet(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& zoneSet);
json::JsonObject GetPersistFancyZonesJSON();
void LoadFancyZonesData();
void SaveZoneSettings() const;
void SaveFancyZonesEditorParameters(bool spanZonesAcrossMonitors, const std::wstring& virtualDesktopId, const HMONITOR& targetMonitor, const std::vector<std::pair<HMONITOR, MONITORINFOEX>>& allMonitors) const;
private:
#if defined(UNIT_TESTS)
friend class FancyZonesUnitTests::FancyZonesDataUnitTests;
friend class FancyZonesUnitTests::FancyZonesIFancyZonesCallbackUnitTests;
friend class FancyZonesUnitTests::WorkAreaUnitTests;
friend class FancyZonesUnitTests::WorkAreaCreationUnitTests;
friend class FancyZonesUnitTests::ZoneSetCalculateZonesUnitTests;
friend class FancyZonesUnitTests::LayoutHotkeysUnitTests;
friend class FancyZonesUnitTests::LayoutTemplatesUnitTests;
friend class FancyZonesUnitTests::CustomLayoutsUnitTests;
inline void SetDeviceInfo(const FancyZonesDataTypes::DeviceIdData& deviceId, FancyZonesDataTypes::DeviceInfoData data)
{
deviceInfoMap[deviceId] = data;
}
inline bool ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON)
{
deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
return !deviceInfoMap.empty();
}
inline void clear_data()
{
appZoneHistoryMap.clear();
deviceInfoMap.clear();
}
friend class FancyZonesUnitTests::AppliedLayoutsUnitTests;
inline void SetSettingsModulePath(std::wstring_view moduleName)
{
@@ -114,27 +48,10 @@ private:
return result + L"\\" + std::wstring(L"zones-settings.json");
}
#endif
// Maps app path to app's zone history data
std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>> appZoneHistoryMap{};
// Maps device unique ID to device data
JSONHelpers::TDeviceInfoMap deviceInfoMap{};
std::wstring settingsFileName;
std::wstring zonesSettingsFileName;
std::wstring appZoneHistoryFileName;
std::wstring editorParametersFileName;
std::function<bool(GUID)> m_virtualDesktopCheckCallback;
mutable std::recursive_mutex dataLock;
};
FancyZonesData& FancyZonesDataInstance();
namespace DefaultValues
{
const int ZoneCount = 3;
const bool ShowSpacing = true;
const int Spacing = 16;
const int SensitivityRadius = 20;
}
FancyZonesData& FancyZonesDataInstance();

View File

@@ -5,8 +5,10 @@
#include <common/logger/logger.h>
#include <common/utils/process_path.h>
#include <FancyZonesLib/GuidUtils.h>
#include <FancyZonesLib/FancyZonesWindowProperties.h>
#include <FancyZonesLib/JsonHelpers.h>
#include <FancyZonesLib/util.h>
AppZoneHistory::AppZoneHistory()
{
@@ -104,7 +106,7 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Dev
auto& perDesktopData = history->second;
for (auto& data : perDesktopData)
{
if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
if (data.deviceId == deviceId)
{
// application already has history on this work area, update it with new window position
data.processIdToHandleMap[processId] = window;
@@ -151,7 +153,7 @@ bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::D
auto& perDesktopData = history->second;
for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);)
{
if (data->deviceId.isEqualWithNullVirtualDesktopId(deviceId) && data->zoneSetUuid == zoneSetId)
if (data->deviceId == deviceId && data->zoneSetUuid == zoneSetId)
{
if (!IsAnotherWindowOfApplicationInstanceZoned(window, deviceId))
{
@@ -209,7 +211,7 @@ std::optional<FancyZonesDataTypes::AppZoneHistoryData> AppZoneHistory::GetZoneHi
auto historyVector = iter->second;
for (const auto& history : historyVector)
{
if (history.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
if (history.deviceId == deviceId)
{
return history;
}
@@ -230,7 +232,7 @@ bool AppZoneHistory::IsAnotherWindowOfApplicationInstanceZoned(HWND window, cons
auto& perDesktopData = history->second;
for (auto& data : perDesktopData)
{
if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
if (data.deviceId == deviceId)
{
DWORD processId = 0;
GetWindowThreadProcessId(window, &processId);
@@ -264,7 +266,7 @@ void AppZoneHistory::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDat
auto& perDesktopData = history->second;
for (auto& data : perDesktopData)
{
if (data.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
if (data.deviceId == deviceId)
{
DWORD processId = 0;
GetWindowThreadProcessId(window, &processId);
@@ -287,7 +289,7 @@ ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZone
const auto& perDesktopData = history->second;
for (const auto& data : perDesktopData)
{
if (data.zoneSetUuid == zoneSetId && data.deviceId.isEqualWithNullVirtualDesktopId(deviceId))
if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId)
{
return data.zoneIndexSet;
}
@@ -298,16 +300,68 @@ ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZone
return {};
}
void AppZoneHistory::RemoveDesktopAppZoneHistory(GUID desktopId)
void AppZoneHistory::SyncVirtualDesktops(GUID currentVirtualDesktopId)
{
_TRACER_;
// Explorer persists current virtual desktop identifier to registry on a per session basis,
// but only after first virtual desktop switch happens. If the user hasn't switched virtual
// desktops in this session value in registry will be empty and we will use default GUID in
// that case (00000000-0000-0000-0000-000000000000).
bool dirtyFlag = false;
for (auto& [path, perDesktopData] : m_history)
{
for (auto& data : perDesktopData)
{
if (data.deviceId.virtualDesktopId == GUID_NULL)
{
data.deviceId.virtualDesktopId = currentVirtualDesktopId;
dirtyFlag = true;
}
else
{
if (m_virtualDesktopCheckCallback && !m_virtualDesktopCheckCallback(data.deviceId.virtualDesktopId))
{
data.deviceId.virtualDesktopId = GUID_NULL;
dirtyFlag = true;
}
}
}
}
if (dirtyFlag)
{
wil::unique_cotaskmem_string virtualDesktopIdStr;
if (SUCCEEDED(StringFromCLSID(currentVirtualDesktopId, &virtualDesktopIdStr)))
{
Logger::info(L"Update Virtual Desktop id to {}", virtualDesktopIdStr.get());
}
SaveData();
}
}
void AppZoneHistory::RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops)
{
std::unordered_set<GUID> active(std::begin(activeDesktops), std::end(activeDesktops));
bool dirtyFlag = false;
for (auto it = std::begin(m_history); it != std::end(m_history);)
{
auto& perDesktopData = it->second;
for (auto desktopIt = std::begin(perDesktopData); desktopIt != std::end(perDesktopData);)
{
if (desktopIt->deviceId.virtualDesktopId == desktopId)
if (desktopIt->deviceId.virtualDesktopId != GUID_NULL && !active.contains(desktopIt->deviceId.virtualDesktopId))
{
auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(desktopIt->deviceId.virtualDesktopId);
if (virtualDesktopIdStr)
{
Logger::info(L"Remove Virtual Desktop id {} from app-zone-history", virtualDesktopIdStr.value());
}
desktopIt = perDesktopData.erase(desktopIt);
dirtyFlag = true;
}
else
{
@@ -324,4 +378,9 @@ void AppZoneHistory::RemoveDesktopAppZoneHistory(GUID desktopId)
++it;
}
}
if (dirtyFlag)
{
SaveData();
}
}

View File

@@ -21,8 +21,6 @@ public:
return saveFolderPath + L"\\app-zone-history.json";
}
void SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback);
void LoadData();
void SaveData();
@@ -38,7 +36,9 @@ public:
void UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId);
ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const;
void RemoveDesktopAppZoneHistory(GUID desktopId);
void SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback);
void SyncVirtualDesktops(GUID currentVirtualDesktopId);
void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops);
private:
AppZoneHistory();

View File

@@ -0,0 +1,420 @@
#include "../pch.h"
#include "AppliedLayouts.h"
#include <common/logger/call_tracer.h>
#include <common/logger/logger.h>
#include <FancyZonesLib/GuidUtils.h>
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
#include <FancyZonesLib/FancyZonesData/LayoutTemplates.h>
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
#include <FancyZonesLib/JsonHelpers.h>
#include <FancyZonesLib/util.h>
namespace JsonUtils
{
struct LayoutJSON
{
static std::optional<Layout> FromJson(const json::JsonObject& json)
{
try
{
Layout data;
auto idStr = json.GetNamedString(NonLocalizable::AppliedLayoutsIds::UuidID);
auto id = FancyZonesUtils::GuidFromString(idStr.c_str());
if (!id.has_value())
{
return std::nullopt;
}
data.uuid = id.value();
data.type = FancyZonesDataTypes::TypeFromString(std::wstring{ json.GetNamedString(NonLocalizable::AppliedLayoutsIds::TypeID) });
data.showSpacing = json.GetNamedBoolean(NonLocalizable::AppliedLayoutsIds::ShowSpacingID);
data.spacing = static_cast<int>(json.GetNamedNumber(NonLocalizable::AppliedLayoutsIds::SpacingID));
data.zoneCount = static_cast<int>(json.GetNamedNumber(NonLocalizable::AppliedLayoutsIds::ZoneCountID));
data.sensitivityRadius = static_cast<int>(json.GetNamedNumber(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, DefaultValues::SensitivityRadius));
return data;
}
catch (const winrt::hresult_error&)
{
return std::nullopt;
}
}
static json::JsonObject ToJson(const Layout& data)
{
json::JsonObject result{};
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::UuidID, json::value(FancyZonesUtils::GuidToString(data.uuid).value()));
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::TypeID, json::value(FancyZonesDataTypes::TypeToString(data.type)));
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ShowSpacingID, json::value(data.showSpacing));
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SpacingID, json::value(data.spacing));
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ZoneCountID, json::value(data.zoneCount));
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(data.sensitivityRadius));
return result;
}
};
struct AppliedLayoutsJSON
{
FancyZonesDataTypes::DeviceIdData deviceId;
Layout data;
static std::optional<AppliedLayoutsJSON> FromJson(const json::JsonObject& json)
{
try
{
AppliedLayoutsJSON result;
std::wstring deviceIdStr = json.GetNamedString(NonLocalizable::AppliedLayoutsIds::DeviceIdID).c_str();
auto deviceId = FancyZonesDataTypes::DeviceIdData::ParseDeviceId(deviceIdStr);
if (!deviceId.has_value())
{
return std::nullopt;
}
auto layout = JsonUtils::LayoutJSON::FromJson(json.GetNamedObject(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID));
if (!layout.has_value())
{
return std::nullopt;
}
result.deviceId = std::move(deviceId.value());
result.data = std::move(layout.value());
return result;
}
catch (const winrt::hresult_error&)
{
return std::nullopt;
}
}
static json::JsonObject ToJson(const AppliedLayoutsJSON& value)
{
json::JsonObject result{};
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::DeviceIdID, json::value(value.deviceId.toString()));
result.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID, JsonUtils::LayoutJSON::ToJson(value.data));
return result;
}
};
AppliedLayouts::TAppliedLayoutsMap ParseJson(const json::JsonObject& json)
{
AppliedLayouts::TAppliedLayoutsMap map{};
auto layouts = json.GetNamedArray(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID);
for (uint32_t i = 0; i < layouts.Size(); ++i)
{
if (auto obj = AppliedLayoutsJSON::FromJson(layouts.GetObjectAt(i)); obj.has_value())
{
map[obj->deviceId] = std::move(obj->data);
}
}
return map;
}
json::JsonObject SerializeJson(const AppliedLayouts::TAppliedLayoutsMap& map)
{
json::JsonObject json{};
json::JsonArray layoutArray{};
for (const auto& [id, data] : map)
{
AppliedLayoutsJSON obj{};
obj.deviceId = id;
obj.data = data;
layoutArray.Append(AppliedLayoutsJSON::ToJson(obj));
}
json.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID, layoutArray);
return json;
}
}
AppliedLayouts::AppliedLayouts()
{
const std::wstring& fileName = AppliedLayoutsFileName();
m_fileWatcher = std::make_unique<FileWatcher>(fileName, [&]() {
PostMessageW(HWND_BROADCAST, WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE, NULL, NULL);
});
}
AppliedLayouts& AppliedLayouts::instance()
{
static AppliedLayouts self;
return self;
}
void AppliedLayouts::LoadData()
{
auto data = json::from_file(AppliedLayoutsFileName());
try
{
if (data)
{
m_layouts = JsonUtils::ParseJson(data.value());
}
else
{
m_layouts.clear();
Logger::info(L"applied-layouts.json file is missing or malformed");
}
}
catch (const winrt::hresult_error& e)
{
Logger::error(L"Parsing applied-layouts error: {}", e.message());
}
}
void AppliedLayouts::SaveData()
{
_TRACER_;
bool dirtyFlag = false;
TAppliedLayoutsMap updatedMap;
if (m_virtualDesktopCheckCallback)
{
for (const auto& [id, data] : m_layouts)
{
auto updatedId = id;
if (!m_virtualDesktopCheckCallback(id.virtualDesktopId))
{
updatedId.virtualDesktopId = GUID_NULL;
dirtyFlag = true;
}
updatedMap.insert({ updatedId, data });
}
}
if (dirtyFlag)
{
json::to_file(AppliedLayoutsFileName(), JsonUtils::SerializeJson(updatedMap));
}
else
{
json::to_file(AppliedLayoutsFileName(), JsonUtils::SerializeJson(m_layouts));
}
}
void AppliedLayouts::SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback)
{
m_virtualDesktopCheckCallback = callback;
}
void AppliedLayouts::SyncVirtualDesktops(GUID currentVirtualDesktopId)
{
_TRACER_;
// Explorer persists current virtual desktop identifier to registry on a per session basis,
// but only after first virtual desktop switch happens. If the user hasn't switched virtual
// desktops in this session value in registry will be empty and we will use default GUID in
// that case (00000000-0000-0000-0000-000000000000).
bool dirtyFlag = false;
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithCurrentId{};
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithNullId{};
for (const auto& [id, data] : m_layouts)
{
if (id.virtualDesktopId == GUID_NULL)
{
replaceWithCurrentId.push_back(id);
dirtyFlag = true;
}
else
{
if (m_virtualDesktopCheckCallback && !m_virtualDesktopCheckCallback(id.virtualDesktopId))
{
replaceWithNullId.push_back(id);
dirtyFlag = true;
}
}
}
for (const auto& id : replaceWithCurrentId)
{
auto mapEntry = m_layouts.extract(id);
mapEntry.key().virtualDesktopId = currentVirtualDesktopId;
m_layouts.insert(std::move(mapEntry));
}
for (const auto& id : replaceWithNullId)
{
auto mapEntry = m_layouts.extract(id);
mapEntry.key().virtualDesktopId = GUID_NULL;
m_layouts.insert(std::move(mapEntry));
}
if (dirtyFlag)
{
wil::unique_cotaskmem_string virtualDesktopIdStr;
if (SUCCEEDED(StringFromCLSID(currentVirtualDesktopId, &virtualDesktopIdStr)))
{
Logger::info(L"Update Virtual Desktop id to {}", virtualDesktopIdStr.get());
}
SaveData();
}
}
void AppliedLayouts::RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops)
{
std::unordered_set<GUID> active(std::begin(activeDesktops), std::end(activeDesktops));
bool dirtyFlag = false;
for (auto it = std::begin(m_layouts); it != std::end(m_layouts);)
{
GUID desktopId = it->first.virtualDesktopId;
if (desktopId != GUID_NULL)
{
auto foundId = active.find(desktopId);
if (foundId == std::end(active))
{
wil::unique_cotaskmem_string virtualDesktopIdStr;
if (SUCCEEDED(StringFromCLSID(desktopId, &virtualDesktopIdStr)))
{
Logger::info(L"Remove Virtual Desktop id {}", virtualDesktopIdStr.get());
}
it = m_layouts.erase(it);
dirtyFlag = true;
continue;
}
}
++it;
}
if (dirtyFlag)
{
SaveData();
}
}
std::optional<Layout> AppliedLayouts::GetDeviceLayout(const FancyZonesDataTypes::DeviceIdData& id) const noexcept
{
auto iter = m_layouts.find(id);
if (iter != m_layouts.end())
{
return iter->second;
}
return std::nullopt;
}
const AppliedLayouts::TAppliedLayoutsMap& AppliedLayouts::GetAppliedLayoutMap() const noexcept
{
return m_layouts;
}
bool AppliedLayouts::IsLayoutApplied(const FancyZonesDataTypes::DeviceIdData& id) const noexcept
{
auto iter = m_layouts.find(id);
return iter != m_layouts.end();
}
bool AppliedLayouts::ApplyLayout(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& layout)
{
auto uuid = FancyZonesUtils::GuidFromString(layout.uuid);
if (!uuid)
{
return false;
}
Layout layoutToApply {
.uuid = uuid.value(),
.type = layout.type,
.showSpacing = DefaultValues::ShowSpacing,
.spacing = DefaultValues::Spacing,
.zoneCount = DefaultValues::ZoneCount,
.sensitivityRadius = DefaultValues::SensitivityRadius,
};
// copy layouts properties to the applied-layout
auto customLayout = CustomLayouts::instance().GetLayout(layoutToApply.uuid);
if (customLayout)
{
if (customLayout.value().type == FancyZonesDataTypes::CustomLayoutType::Grid)
{
auto layoutInfo = std::get<FancyZonesDataTypes::GridLayoutInfo>(customLayout.value().info);
layoutToApply.sensitivityRadius = layoutInfo.sensitivityRadius();
layoutToApply.showSpacing = layoutInfo.showSpacing();
layoutToApply.spacing = layoutInfo.spacing();
layoutToApply.zoneCount = layoutInfo.zoneCount();
}
else if (customLayout.value().type == FancyZonesDataTypes::CustomLayoutType::Canvas)
{
auto layoutInfo = std::get<FancyZonesDataTypes::CanvasLayoutInfo>(customLayout.value().info);
layoutToApply.sensitivityRadius = layoutInfo.sensitivityRadius;
layoutToApply.zoneCount = (int)layoutInfo.zones.size();
}
}
else
{
// check templates only if it wasn't a custom layout, since templates don't have ids yet
auto templateLayout = LayoutTemplates::instance().GetLayout(layout.type);
if (templateLayout)
{
auto layoutInfo = templateLayout.value();
layoutToApply.sensitivityRadius = layoutInfo.sensitivityRadius;
layoutToApply.showSpacing = layoutInfo.showSpacing;
layoutToApply.spacing = layoutInfo.spacing;
layoutToApply.zoneCount = layoutInfo.zoneCount;
}
}
m_layouts[deviceId] = std::move(layoutToApply);
return true;
}
bool AppliedLayouts::ApplyDefaultLayout(const FancyZonesDataTypes::DeviceIdData& deviceId)
{
Logger::info(L"Set default layout on {}", deviceId.toString());
GUID guid;
auto result{ CoCreateGuid(&guid) };
if (!SUCCEEDED(result))
{
Logger::error("Failed to create an ID for the new layout");
return false;
}
Layout layout{
.uuid = guid,
.type = FancyZonesDataTypes::ZoneSetLayoutType::PriorityGrid,
.showSpacing = DefaultValues::ShowSpacing,
.spacing = DefaultValues::Spacing,
.zoneCount = DefaultValues::ZoneCount,
.sensitivityRadius = DefaultValues::SensitivityRadius
};
m_layouts[deviceId] = std::move(layout);
SaveData();
return true;
}
bool AppliedLayouts::CloneLayout(const FancyZonesDataTypes::DeviceIdData& srcId, const FancyZonesDataTypes::DeviceIdData& dstId)
{
if (srcId == dstId || m_layouts.find(srcId) == m_layouts.end())
{
return false;
}
Logger::info(L"Clone layout from {} to {}", dstId.toString(), srcId.toString());
m_layouts[dstId] = m_layouts[srcId];
SaveData();
return true;
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <map>
#include <memory>
#include <optional>
#include <FancyZonesLib/FancyZonesData/Layout.h>
#include <FancyZonesLib/ModuleConstants.h>
#include <common/SettingsAPI/FileWatcher.h>
#include <common/SettingsAPI/settings_helpers.h>
namespace NonLocalizable
{
namespace AppliedLayoutsIds
{
const static wchar_t* AppliedLayoutsArrayID = L"applied-layouts";
const static wchar_t* DeviceIdID = L"device-id";
const static wchar_t* AppliedLayoutID = L"applied-layout";
const static wchar_t* UuidID = L"uuid";
const static wchar_t* TypeID = L"type";
const static wchar_t* ShowSpacingID = L"show-spacing";
const static wchar_t* SpacingID = L"spacing";
const static wchar_t* ZoneCountID = L"zone-count";
const static wchar_t* SensitivityRadiusID = L"sensitivity-radius";
}
}
class AppliedLayouts
{
public:
using TAppliedLayoutsMap = std::unordered_map<FancyZonesDataTypes::DeviceIdData, Layout>;
static AppliedLayouts& instance();
inline static std::wstring AppliedLayoutsFileName()
{
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
#if defined(UNIT_TESTS)
return saveFolderPath + L"\\test-applied-layouts.json";
#endif
return saveFolderPath + L"\\applied-layouts.json";
}
void LoadData();
void SaveData();
void SetVirtualDesktopCheckCallback(std::function<bool(GUID)> callback);
void SyncVirtualDesktops(GUID currentVirtualDesktopId);
void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops);
std::optional<Layout> GetDeviceLayout(const FancyZonesDataTypes::DeviceIdData& id) const noexcept;
const TAppliedLayoutsMap& GetAppliedLayoutMap() const noexcept;
bool IsLayoutApplied(const FancyZonesDataTypes::DeviceIdData& id) const noexcept;
bool ApplyLayout(const FancyZonesDataTypes::DeviceIdData& deviceId, const FancyZonesDataTypes::ZoneSetData& layout);
bool ApplyDefaultLayout(const FancyZonesDataTypes::DeviceIdData& deviceId);
bool CloneLayout(const FancyZonesDataTypes::DeviceIdData& srcId, const FancyZonesDataTypes::DeviceIdData& dstId);
private:
AppliedLayouts();
~AppliedLayouts() = default;
std::unique_ptr<FileWatcher> m_fileWatcher;
TAppliedLayoutsMap m_layouts;
std::function<bool(GUID)> m_virtualDesktopCheckCallback;
};

View File

@@ -3,7 +3,7 @@
#include <common/logger/logger.h>
#include <FancyZonesLib/FancyZonesData.h> // layout defaults
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
#include <FancyZonesLib/JsonHelpers.h>
#include <FancyZonesLib/util.h>

View File

@@ -0,0 +1,15 @@
#pragma once
#include <guiddef.h>
#include <FancyZonesLib/FancyZonesDataTypes.h>
struct Layout
{
GUID uuid;
FancyZonesDataTypes::ZoneSetLayoutType type;
bool showSpacing;
int spacing;
int zoneCount;
int sensitivityRadius;
};

View File

@@ -0,0 +1,9 @@
#pragma once
namespace DefaultValues
{
const int ZoneCount = 3;
const bool ShowSpacing = true;
const int Spacing = 16;
const int SensitivityRadius = 20;
}

View File

@@ -0,0 +1,100 @@
#include "../pch.h"
#include "LayoutTemplates.h"
#include <common/logger/logger.h>
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
namespace JsonUtils
{
struct TemplateLayoutJSON
{
static std::optional<Layout> FromJson(const json::JsonObject& json)
{
try
{
Layout data;
data.uuid = GUID_NULL;
data.type = FancyZonesDataTypes::TypeFromString(std::wstring{ json.GetNamedString(NonLocalizable::LayoutTemplatesIds::TypeID) });
data.showSpacing = json.GetNamedBoolean(NonLocalizable::LayoutTemplatesIds::ShowSpacingID, DefaultValues::ShowSpacing);
data.spacing = static_cast<int>(json.GetNamedNumber(NonLocalizable::LayoutTemplatesIds::SpacingID, DefaultValues::Spacing));
data.zoneCount = static_cast<int>(json.GetNamedNumber(NonLocalizable::LayoutTemplatesIds::ZoneCountID, DefaultValues::ZoneCount));
data.sensitivityRadius = static_cast<int>(json.GetNamedNumber(NonLocalizable::LayoutTemplatesIds::SensitivityRadiusID, DefaultValues::SensitivityRadius));
return data;
}
catch (const winrt::hresult_error&)
{
return std::nullopt;
}
}
};
std::vector<Layout> ParseJson(const json::JsonObject& json)
{
std::vector<Layout> vec{};
auto layouts = json.GetNamedArray(NonLocalizable::LayoutTemplatesIds::LayoutTemplatesArrayID);
for (uint32_t i = 0; i < layouts.Size(); ++i)
{
if (auto obj = TemplateLayoutJSON::FromJson(layouts.GetObjectAt(i)); obj.has_value())
{
vec.emplace_back(std::move(obj.value()));
}
}
return vec;
}
}
LayoutTemplates::LayoutTemplates()
{
const std::wstring& fileName = LayoutTemplatesFileName();
m_fileWatcher = std::make_unique<FileWatcher>(fileName, [&]() {
PostMessageW(HWND_BROADCAST, WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE, NULL, NULL);
});
}
LayoutTemplates& LayoutTemplates::instance()
{
static LayoutTemplates self;
return self;
}
void LayoutTemplates::LoadData()
{
auto data = json::from_file(LayoutTemplatesFileName());
try
{
if (data)
{
m_layouts = JsonUtils::ParseJson(data.value());
}
else
{
m_layouts.clear();
Logger::info(L"layout-templates.json file is missing or malformed");
}
}
catch (const winrt::hresult_error& e)
{
Logger::error(L"Parsing layout-templates error: {}", e.message());
}
}
std::optional<Layout> LayoutTemplates::GetLayout(FancyZonesDataTypes::ZoneSetLayoutType type) const noexcept
{
for (const auto& layout : m_layouts)
{
if (layout.type == type)
{
return layout;
}
}
return std::nullopt;
}

View File

@@ -1,7 +1,9 @@
#pragma once
#include <FancyZonesLib/FancyZonesData/Layout.h>
#include <FancyZonesLib/ModuleConstants.h>
#include <common/SettingsAPI/FileWatcher.h>
#include <common/SettingsAPI/settings_helpers.h>
namespace NonLocalizable
@@ -9,12 +11,19 @@ namespace NonLocalizable
namespace LayoutTemplatesIds
{
const static wchar_t* LayoutTemplatesArrayID = L"layout-templates";
const static wchar_t* TypeID = L"type";
const static wchar_t* ShowSpacingID = L"show-spacing";
const static wchar_t* SpacingID = L"spacing";
const static wchar_t* ZoneCountID = L"zone-count";
const static wchar_t* SensitivityRadiusID = L"sensitivity-radius";
}
}
class LayoutTemplates
{
public:
static LayoutTemplates& instance();
inline static std::wstring LayoutTemplatesFileName()
{
std::wstring saveFolderPath = PTSettingsHelper::get_module_save_folder_location(NonLocalizable::ModuleKey);
@@ -23,4 +32,15 @@ public:
#endif
return saveFolderPath + L"\\layout-templates.json";
}
void LoadData();
std::optional<Layout> GetLayout(FancyZonesDataTypes::ZoneSetLayoutType type) const noexcept;
private:
LayoutTemplates();
~LayoutTemplates() = default;
std::unique_ptr<FileWatcher> m_fileWatcher;
std::vector<Layout> m_layouts;
};

View File

@@ -305,9 +305,4 @@ namespace FancyZonesDataTypes
return result;
}
bool DeviceIdData::isEqualWithNullVirtualDesktopId(const DeviceIdData& other) const
{
return deviceName.compare(other.deviceName) == 0 && width == other.width && height == other.height && (virtualDesktopId == other.virtualDesktopId || virtualDesktopId == GUID_NULL || other.virtualDesktopId == GUID_NULL) && monitorId.compare(other.monitorId) == 0;
}
}

View File

@@ -125,7 +125,6 @@ namespace FancyZonesDataTypes
static bool IsValidDeviceId(const std::wstring& str);
std::wstring toString() const;
bool isEqualWithNullVirtualDesktopId(const DeviceIdData& other) const;
};
struct AppZoneHistoryData
@@ -153,7 +152,7 @@ namespace FancyZonesDataTypes
inline bool operator==(const DeviceIdData& lhs, const DeviceIdData& rhs)
{
return lhs.deviceName.compare(rhs.deviceName) == 0 && lhs.width == rhs.width && lhs.height == rhs.height && lhs.virtualDesktopId == rhs.virtualDesktopId && lhs.monitorId.compare(rhs.monitorId) == 0;
return lhs.deviceName.compare(rhs.deviceName) == 0 && lhs.width == rhs.width && lhs.height == rhs.height && (lhs.virtualDesktopId == rhs.virtualDesktopId || lhs.virtualDesktopId == GUID_NULL || rhs.virtualDesktopId == GUID_NULL) && lhs.monitorId.compare(rhs.monitorId) == 0;
}
inline bool operator!=(const DeviceIdData& lhs, const DeviceIdData& rhs)

View File

@@ -38,9 +38,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="FancyZonesData\CustomLayouts.h" />
<ClInclude Include="FancyZonesData\AppliedLayouts.h" />
<ClInclude Include="FancyZonesData\AppZoneHistory.h" />
<ClInclude Include="FancyZones.h" />
<ClInclude Include="FancyZonesDataTypes.h" />
<ClInclude Include="FancyZonesData\Layout.h" />
<ClInclude Include="FancyZonesData\LayoutDefaults.h" />
<ClInclude Include="FancyZonesData\LayoutTemplates.h" />
<ClInclude Include="FancyZonesWinHookEventIDs.h" />
<ClInclude Include="GenericKeyHook.h" />
@@ -79,6 +82,14 @@
</ClCompile>
<ClCompile Include="FancyZones.cpp" />
<ClCompile Include="FancyZonesDataTypes.cpp" />
<ClCompile Include="FancyZonesData\AppliedLayouts.cpp">
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="FancyZonesData\LayoutTemplates.cpp">
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
<ClCompile Include="FancyZonesData.cpp" />
<ClCompile Include="JsonHelpers.cpp" />

View File

@@ -93,6 +93,9 @@
<ClInclude Include="FancyZonesData\AppZoneHistory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FancyZonesData\AppliedLayouts.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FancyZonesData\CustomLayouts.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -105,6 +108,12 @@
<ClInclude Include="FancyZonesData\LayoutTemplates.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FancyZonesData\LayoutDefaults.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FancyZonesData\Layout.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@@ -173,6 +182,12 @@
<ClCompile Include="FancyZonesData\AppZoneHistory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FancyZonesData\AppliedLayouts.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FancyZonesData\LayoutTemplates.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -11,9 +11,10 @@ UINT WM_PRIV_VD_INIT;
UINT WM_PRIV_VD_SWITCH;
UINT WM_PRIV_VD_UPDATE;
UINT WM_PRIV_EDITOR;
UINT WM_PRIV_FILE_UPDATE;
UINT WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE;
UINT WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE;
UINT WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE;
UINT WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE;
UINT WM_PRIV_SNAP_HOTKEY;
UINT WM_PRIV_QUICK_LAYOUT_KEY;
UINT WM_PRIV_SETTINGS_CHANGED;
@@ -32,9 +33,10 @@ void InitializeWinhookEventIds()
WM_PRIV_VD_SWITCH = RegisterWindowMessage(L"{128c2cb0-6bdf-493e-abbe-f8705e04aa95}");
WM_PRIV_VD_UPDATE = RegisterWindowMessage(L"{b8b72b46-f42f-4c26-9e20-29336cf2f22e}");
WM_PRIV_EDITOR = RegisterWindowMessage(L"{87543824-7080-4e91-9d9c-0404642fc7b6}");
WM_PRIV_FILE_UPDATE = RegisterWindowMessage(L"{632f17a9-55a7-45f1-a4db-162e39271d92}");
WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE = RegisterWindowMessage(L"{07229b7e-4f22-4357-b136-33c289be2295}");
WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE = RegisterWindowMessage(L"{4686f019-5d3d-4c5c-9051-b7cbbccca77d}");
WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE = RegisterWindowMessage(L"{0972787e-cdab-4e16-b228-91acdc38f40f}");
WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE = RegisterWindowMessage(L"{2ef2c8a7-e0d5-4f31-9ede-52aade2d284d}");
WM_PRIV_SNAP_HOTKEY = RegisterWindowMessage(L"{72f4fd8e-23f1-43ab-bbbc-029363df9a84}");
WM_PRIV_QUICK_LAYOUT_KEY = RegisterWindowMessage(L"{15baab3d-c67b-4a15-aFF0-13610e05e947}");
WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{89ca3Daa-bf2d-4e73-9f3f-c60716364e27}");

View File

@@ -9,9 +9,10 @@ extern UINT WM_PRIV_VD_INIT; // Scheduled when FancyZones is initialized
extern UINT WM_PRIV_VD_SWITCH; // Scheduled when virtual desktop switch occurs
extern UINT WM_PRIV_VD_UPDATE; // Scheduled on virtual desktops update (creation/deletion)
extern UINT WM_PRIV_EDITOR; // Scheduled when the editor exits
extern UINT WM_PRIV_FILE_UPDATE; // Scheduled when the watched zone-settings file is updated
extern UINT WM_PRIV_LAYOUT_HOTKEYS_FILE_UPDATE; // Scheduled when the watched layout-hotkeys.json file is updated
extern UINT WM_PRIV_LAYOUT_TEMPLATES_FILE_UPDATE; // Scheduled when the watched layout-templates.json file is updated
extern UINT WM_PRIV_CUSTOM_LAYOUTS_FILE_UPDATE; // Scheduled when the watched custom-layouts.json file is updated
extern UINT WM_PRIV_APPLIED_LAYOUTS_FILE_UPDATE; // Scheduled when the watched applied-layouts.json file is updated
extern UINT WM_PRIV_SNAP_HOTKEY; // Scheduled when we receive a snap hotkey key down press
extern UINT WM_PRIV_QUICK_LAYOUT_KEY; // Scheduled when we receive a key down press to quickly apply a layout
extern UINT WM_PRIV_SETTINGS_CHANGED; // Scheduled when the a watched settings file is updated

View File

@@ -1,12 +1,13 @@
#include "pch.h"
#include "JsonHelpers.h"
#include "FancyZonesData.h"
#include "FancyZonesDataTypes.h"
#include "trace.h"
#include "util.h"
#include <FancyZonesLib/FancyZonesData/AppliedLayouts.h>
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
#include <FancyZonesLib/FancyZonesData/LayoutHotkeys.h>
#include <FancyZonesLib/FancyZonesData/LayoutTemplates.h>
@@ -580,21 +581,6 @@ namespace JSONHelpers
}
}
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap)
{
auto before = json::from_file(zonesSettingsFileName);
json::JsonObject root{};
root.SetNamedValue(NonLocalizable::DevicesStr, JSONHelpers::SerializeDeviceInfos(deviceInfoMap));
if (!before.has_value() || before.value().Stringify() != root.Stringify())
{
Trace::FancyZones::DataChanged();
json::to_file(zonesSettingsFileName, root);
}
}
void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap)
{
json::JsonObject root{};
@@ -644,7 +630,7 @@ namespace JSONHelpers
return appHistoryArray;
}
TDeviceInfoMap ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON)
std::optional<TDeviceInfoMap> ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON)
{
try
{
@@ -661,22 +647,37 @@ namespace JSONHelpers
return std::move(deviceInfoMap);
}
catch (const winrt::hresult_error&)
catch (const winrt::hresult_error& e)
{
return {};
Logger::error(L"Parsing device info error: {}", e.message());
return std::nullopt;
}
}
json::JsonArray SerializeDeviceInfos(const TDeviceInfoMap& deviceInfoMap)
void SaveAppliedLayouts(const TDeviceInfoMap& deviceInfoMap)
{
json::JsonArray DeviceInfosJSON{};
json::JsonObject root{};
json::JsonArray layoutsArray{};
for (const auto& [deviceID, deviceData] : deviceInfoMap)
for (const auto& [deviceID, data] : deviceInfoMap)
{
DeviceInfosJSON.Append(DeviceInfoJSON::DeviceInfoJSON::ToJson(DeviceInfoJSON{ deviceID, deviceData }));
json::JsonObject layout{};
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::UuidID, json::value(data.activeZoneSet.uuid));
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::TypeID, json::value(FancyZonesDataTypes::TypeToString(data.activeZoneSet.type)));
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ShowSpacingID, json::value(data.showSpacing));
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SpacingID, json::value(data.spacing));
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::ZoneCountID, json::value(data.zoneCount));
layout.SetNamedValue(NonLocalizable::AppliedLayoutsIds::SensitivityRadiusID, json::value(data.sensitivityRadius));
json::JsonObject obj{};
obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::DeviceIdID, json::value(deviceID.toString()));
obj.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutID, layout);
layoutsArray.Append(obj);
}
return DeviceInfosJSON;
root.SetNamedValue(NonLocalizable::AppliedLayoutsIds::AppliedLayoutsArrayID, layoutsArray);
json::to_file(AppliedLayouts::AppliedLayoutsFileName(), root);
}
json::JsonArray SerializeCustomZoneSets(const TCustomZoneSetsMap& customZoneSetsMap)

View File

@@ -93,14 +93,13 @@ namespace JSONHelpers
json::JsonObject GetPersistFancyZonesJSON(const std::wstring& zonesSettingsFileName, const std::wstring& appZoneHistoryFileName);
void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap);
void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap);
TAppZoneHistoryMap ParseAppZoneHistory(const json::JsonObject& fancyZonesDataJSON);
json::JsonArray SerializeAppZoneHistory(const TAppZoneHistoryMap& appZoneHistoryMap);
void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap);
TDeviceInfoMap ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON);
json::JsonArray SerializeDeviceInfos(const TDeviceInfoMap& deviceInfoMap);
// replace zones-settings: applied layouts
std::optional<TDeviceInfoMap> ParseDeviceInfos(const json::JsonObject& fancyZonesDataJSON);
void SaveAppliedLayouts(const TDeviceInfoMap& deviceInfoMap);
// replace zones-settings: layout hotkeys
std::optional<TLayoutQuickKeysMap> ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON);

View File

@@ -4,7 +4,7 @@
#include <common/logger/call_tracer.h>
#include <common/logger/logger.h>
#include "FancyZonesData.h"
#include "FancyZonesData/AppliedLayouts.h"
#include "FancyZonesData/AppZoneHistory.h"
#include "FancyZonesDataTypes.h"
#include "ZonesOverlay.h"
@@ -486,73 +486,65 @@ void WorkArea::InitializeZoneSets(const FancyZonesDataTypes::DeviceIdData& paren
wil::unique_cotaskmem_string virtualDesktopId;
if (SUCCEEDED(StringFromCLSID(m_uniqueId.virtualDesktopId, &virtualDesktopId)))
{
Logger::debug(L"Initialize zone sets on the virtual desktop {}", virtualDesktopId.get());
Logger::debug(L"Initialize layout on the virtual desktop {}", virtualDesktopId.get());
}
bool deviceAdded = FancyZonesDataInstance().AddDevice(m_uniqueId);
// If the device has been added, check if it should inherit the parent's layout
if (deviceAdded && parentUniqueId.virtualDesktopId != GUID_NULL)
bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId);
if (!isLayoutAlreadyApplied)
{
FancyZonesDataInstance().CloneDeviceInfo(parentUniqueId, m_uniqueId);
if (parentUniqueId.virtualDesktopId != GUID_NULL)
{
AppliedLayouts::instance().CloneLayout(parentUniqueId, m_uniqueId);
}
else
{
AppliedLayouts::instance().ApplyDefaultLayout(m_uniqueId);
}
}
CalculateZoneSet(m_overlappingAlgorithm);
}
void WorkArea::CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept
{
const auto& fancyZonesData = FancyZonesDataInstance();
const auto deviceInfoData = fancyZonesData.FindDeviceInfo(m_uniqueId);
if (!deviceInfoData.has_value())
const auto appliedLayout = AppliedLayouts::instance().GetDeviceLayout(m_uniqueId);
if (!appliedLayout.has_value())
{
return;
}
const auto& activeZoneSet = deviceInfoData->activeZoneSet;
auto zoneSet = MakeZoneSet(ZoneSetConfig(
appliedLayout->uuid,
appliedLayout->type,
m_monitor,
appliedLayout->sensitivityRadius,
overlappingAlgorithm));
if (activeZoneSet.uuid.empty())
RECT workArea;
if (m_monitor)
{
return;
}
GUID zoneSetId;
if (SUCCEEDED_LOG(CLSIDFromString(activeZoneSet.uuid.c_str(), &zoneSetId)))
{
int sensitivityRadius = deviceInfoData->sensitivityRadius;
auto zoneSet = MakeZoneSet(ZoneSetConfig(
zoneSetId,
activeZoneSet.type,
m_monitor,
sensitivityRadius,
overlappingAlgorithm));
RECT workArea;
if (m_monitor)
MONITORINFO monitorInfo{};
monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfoW(m_monitor, &monitorInfo))
{
MONITORINFO monitorInfo{};
monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfoW(m_monitor, &monitorInfo))
{
workArea = monitorInfo.rcWork;
}
else
{
return;
}
workArea = monitorInfo.rcWork;
}
else
{
workArea = GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
return;
}
bool showSpacing = deviceInfoData->showSpacing;
int spacing = showSpacing ? deviceInfoData->spacing : 0;
int zoneCount = deviceInfoData->zoneCount;
zoneSet->CalculateZones(workArea, zoneCount, spacing);
UpdateActiveZoneSet(zoneSet.get());
}
else
{
workArea = GetAllMonitorsCombinedRect<&MONITORINFO::rcWork>();
}
bool showSpacing = appliedLayout->showSpacing;
int spacing = showSpacing ? appliedLayout->spacing : 0;
int zoneCount = appliedLayout->zoneCount;
zoneSet->CalculateZones(workArea, zoneCount, spacing);
UpdateActiveZoneSet(zoneSet.get());
}
void WorkArea::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
@@ -568,7 +560,8 @@ void WorkArea::UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept
.uuid = zoneSetId.get(),
.type = m_zoneSet->LayoutType()
};
FancyZonesDataInstance().SetActiveZoneSet(m_uniqueId, data);
AppliedLayouts::instance().ApplyLayout(m_uniqueId, data);
}
}
}

View File

@@ -2,7 +2,6 @@
#include "ZoneSet.h"
#include "FancyZonesData.h"
#include <FancyZonesLib/FancyZonesData/CustomLayouts.h>
#include "FancyZonesDataTypes.h"
#include "FancyZonesWindowProperties.h"

View File

@@ -2,8 +2,8 @@
#include "trace.h"
#include "FancyZonesLib/ZoneSet.h"
#include "FancyZonesLib/Settings.h"
#include "FancyZonesLib/FancyZonesData.h"
#include "FancyZonesData/AppZoneHistory.h"
#include "FancyZonesLib/FancyZonesData/AppliedLayouts.h"
#include "FancyZonesLib/FancyZonesData/CustomLayouts.h"
#include "FancyZonesLib/FancyZonesData/LayoutHotkeys.h"
#include "FancyZonesLib/FancyZonesDataTypes.h"
@@ -145,10 +145,9 @@ void Trace::FancyZones::OnKeyDown(DWORD vkCode, bool win, bool control, bool inM
void Trace::FancyZones::DataChanged() noexcept
{
const FancyZonesData& data = FancyZonesDataInstance();
int appsHistorySize = static_cast<int>(AppZoneHistory::instance().GetFullAppZoneHistory().size());
const auto& customZones = CustomLayouts::instance().GetAllLayouts();
const auto& devices = data.GetDeviceInfoMap();
const auto& layouts = AppliedLayouts::instance().GetAppliedLayoutMap();
auto quickKeysCount = LayoutHotkeys::instance().GetHotkeysCount();
std::unique_ptr<INT32[]> customZonesArray(new (std::nothrow) INT32[customZones.size()]);
@@ -157,7 +156,7 @@ void Trace::FancyZones::DataChanged() noexcept
return;
}
auto getCustomZoneCount = [&data](const std::variant<FancyZonesDataTypes::CanvasLayoutInfo, FancyZonesDataTypes::GridLayoutInfo>& layoutInfo) -> int {
auto getCustomZoneCount = [](const std::variant<FancyZonesDataTypes::CanvasLayoutInfo, FancyZonesDataTypes::GridLayoutInfo>& layoutInfo) -> int {
if (std::holds_alternative<FancyZonesDataTypes::GridLayoutInfo>(layoutInfo))
{
const auto& info = std::get<FancyZonesDataTypes::GridLayoutInfo>(layoutInfo);
@@ -181,9 +180,9 @@ void Trace::FancyZones::DataChanged() noexcept
// ActiveZoneSetsList
std::wstring activeZoneSetInfo;
for (const auto& [id, device] : devices)
for (const auto& [id, layout] : layouts)
{
const FancyZonesDataTypes::ZoneSetLayoutType type = device.activeZoneSet.type;
const FancyZonesDataTypes::ZoneSetLayoutType type = layout.type;
if (!activeZoneSetInfo.empty())
{
activeZoneSetInfo += L"; ";
@@ -193,19 +192,16 @@ void Trace::FancyZones::DataChanged() noexcept
int zoneCount = -1;
if (type == FancyZonesDataTypes::ZoneSetLayoutType::Custom)
{
auto guid = FancyZonesUtils::GuidFromString(device.activeZoneSet.uuid);
if (guid)
auto guid = layout.uuid;
const auto& activeCustomZone = customZones.find(guid);
if (activeCustomZone != customZones.end())
{
const auto& activeCustomZone = customZones.find(guid.value());
if (activeCustomZone != customZones.end())
{
zoneCount = getCustomZoneCount(activeCustomZone->second.info);
}
}
zoneCount = getCustomZoneCount(activeCustomZone->second.info);
}
}
else
{
zoneCount = device.zoneCount;
zoneCount = layout.zoneCount;
}
if (zoneCount != -1)
@@ -226,7 +222,7 @@ void Trace::FancyZones::DataChanged() noexcept
TraceLoggingInt32(appsHistorySize, AppsInHistoryCountKey),
TraceLoggingInt32(static_cast<int>(customZones.size()), CustomZoneSetCountKey),
TraceLoggingInt32Array(customZonesArray.get(), static_cast<int>(customZones.size()), NumberOfZonesForEachCustomZoneSetKey),
TraceLoggingInt32(static_cast<int>(devices.size()), ActiveZoneSetsCountKey),
TraceLoggingInt32(static_cast<int>(layouts.size()), ActiveZoneSetsCountKey),
TraceLoggingWideString(activeZoneSetInfo.c_str(), ActiveZoneSetsListKey),
TraceLoggingInt32(static_cast<int>(quickKeysCount), LayoutUsingQuickKeyCountKey));
}