[FancyZones]Monitor identification (#19077)

* moved monitors identifying

* changed device id

* get wmi info

* convert old data

* save/load applied layouts

* changed monitor identification

* id comparison

* save/load app zone history

* moved com and security init

* update ids in editor

* lib fix

* updated tests

* changed comparison

* tests

* updated id comparison

* updated log

* moved definition

* spell check

* resolve conflicts

* refactoring

* update serial numbers if possible
This commit is contained in:
Seraphima Zykova
2022-07-01 17:29:02 +02:00
committed by GitHub
parent 3cb0638c7e
commit 35bb4280d0
30 changed files with 1084 additions and 408 deletions

View File

@@ -667,6 +667,8 @@ globals
GNumber GNumber
google google
GPTR GPTR
GSM
gsuberland
gtm gtm
gui gui
guiddef guiddef
@@ -2103,6 +2105,7 @@ Udp
uefi uefi
UHash UHash
UIA UIA
uid
Uid Uid
uint uint
uintptr uintptr

View File

@@ -110,7 +110,7 @@
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shcore.lib;shlwapi.lib;DbgHelp.lib;uxtheme.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>shcore.lib;shlwapi.lib;DbgHelp.lib;uxtheme.lib;dwmapi.lib;wbemuuid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'"> <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
@@ -128,7 +128,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>shcore.lib;shlwapi.lib;DbgHelp.lib;uxtheme.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>shcore.lib;shlwapi.lib;DbgHelp.lib;uxtheme.lib;dwmapi.lib;wbemuuid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

View File

@@ -2,6 +2,7 @@
#include "EditorParameters.h" #include "EditorParameters.h"
#include <FancyZonesLib/FancyZonesWindowProperties.h> #include <FancyZonesLib/FancyZonesWindowProperties.h>
#include <FancyZonesLib/MonitorUtils.h>
#include <FancyZonesLib/on_thread_executor.h> #include <FancyZonesLib/on_thread_executor.h>
#include <FancyZonesLib/Settings.h> #include <FancyZonesLib/Settings.h>
#include <FancyZonesLib/VirtualDesktop.h> #include <FancyZonesLib/VirtualDesktop.h>
@@ -22,6 +23,8 @@ namespace JsonUtils
struct MonitorInfo struct MonitorInfo
{ {
std::wstring monitorName; std::wstring monitorName;
std::wstring monitorInstanceId;
std::wstring monitorSerialNumber;
std::wstring virtualDesktop; std::wstring virtualDesktop;
int dpi; int dpi;
int top; int top;
@@ -37,6 +40,8 @@ namespace JsonUtils
json::JsonObject result{}; json::JsonObject result{};
result.SetNamedValue(NonLocalizable::EditorParametersIds::MonitorNameId, json::value(monitor.monitorName)); result.SetNamedValue(NonLocalizable::EditorParametersIds::MonitorNameId, json::value(monitor.monitorName));
result.SetNamedValue(NonLocalizable::EditorParametersIds::MonitorInstanceId, json::value(monitor.monitorInstanceId));
result.SetNamedValue(NonLocalizable::EditorParametersIds::MonitorSerialNumberId, json::value(monitor.monitorSerialNumber));
result.SetNamedValue(NonLocalizable::EditorParametersIds::VirtualDesktopId, json::value(monitor.virtualDesktop)); result.SetNamedValue(NonLocalizable::EditorParametersIds::VirtualDesktopId, json::value(monitor.virtualDesktop));
result.SetNamedValue(NonLocalizable::EditorParametersIds::Dpi, json::value(monitor.dpi)); result.SetNamedValue(NonLocalizable::EditorParametersIds::Dpi, json::value(monitor.dpi));
result.SetNamedValue(NonLocalizable::EditorParametersIds::TopCoordinate, json::value(monitor.top)); result.SetNamedValue(NonLocalizable::EditorParametersIds::TopCoordinate, json::value(monitor.top));
@@ -82,7 +87,7 @@ bool EditorParameters::Save() noexcept
const auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(VirtualDesktop::instance().GetCurrentVirtualDesktopId()); const auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(VirtualDesktop::instance().GetCurrentVirtualDesktopId());
if (!virtualDesktopIdStr) if (!virtualDesktopIdStr)
{ {
Logger::error(L"Save editor params: no virtual desktop id"); Logger::error(L"Save editor params: invalid virtual desktop id");
return false; return false;
} }
@@ -124,13 +129,7 @@ bool EditorParameters::Save() noexcept
} }
else else
{ {
// device id map for correct device ids auto monitors = MonitorUtils::IdentifyMonitors();
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap;
std::vector<std::pair<HMONITOR, MONITORINFOEX>> allMonitors;
dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&]() {
allMonitors = FancyZonesUtils::GetAllMonitorInfo<&MONITORINFOEX::rcWork>();
} }).wait();
HMONITOR targetMonitor{}; HMONITOR targetMonitor{};
if (FancyZonesSettings::settings().use_cursorpos_editor_startupscreen) if (FancyZonesSettings::settings().use_cursorpos_editor_startupscreen)
@@ -150,21 +149,29 @@ bool EditorParameters::Save() noexcept
return false; return false;
} }
for (auto& monitorData : allMonitors) for (auto& monitorData : monitors)
{ {
HMONITOR monitor = monitorData.first; HMONITOR monitor = monitorData.monitor;
auto monitorInfo = monitorData.second;
MONITORINFOEX monitorInfo{};
dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
monitorInfo.cbSize = sizeof(monitorInfo);
if (!GetMonitorInfo(monitor, &monitorInfo))
{
return;
}
} }).wait();
JsonUtils::MonitorInfo monitorJson; JsonUtils::MonitorInfo monitorJson;
std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(monitorInfo.szDevice, displayDeviceIdxMap);
if (monitor == targetMonitor) if (monitor == targetMonitor)
{ {
monitorJson.isSelected = true; /* Is monitor selected for the main editor window opening */ monitorJson.isSelected = true; /* Is monitor selected for the main editor window opening */
} }
monitorJson.monitorName = FancyZonesUtils::TrimDeviceId(deviceId); monitorJson.monitorName = monitorData.deviceId.id;
monitorJson.monitorInstanceId = monitorData.deviceId.instanceId;
monitorJson.monitorSerialNumber = monitorData.serialNumber;
monitorJson.virtualDesktop = virtualDesktopIdStr.value(); monitorJson.virtualDesktop = virtualDesktopIdStr.value();
UINT dpi = 0; UINT dpi = 0;

View File

@@ -6,6 +6,8 @@ namespace NonLocalizable
{ {
const static wchar_t* Dpi = L"dpi"; const static wchar_t* Dpi = L"dpi";
const static wchar_t* MonitorNameId = L"monitor"; const static wchar_t* MonitorNameId = L"monitor";
const static wchar_t* MonitorInstanceId = L"monitor-instance-id";
const static wchar_t* MonitorSerialNumberId = L"monitor-serial-number";
const static wchar_t* VirtualDesktopId = L"virtual-desktop"; const static wchar_t* VirtualDesktopId = L"virtual-desktop";
const static wchar_t* TopCoordinate = L"top-coordinate"; const static wchar_t* TopCoordinate = L"top-coordinate";
const static wchar_t* LeftCoordinate = L"left-coordinate"; const static wchar_t* LeftCoordinate = L"left-coordinate";

View File

@@ -146,7 +146,7 @@ public:
LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept; LRESULT WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
void OnDisplayChange(DisplayChangeType changeType) noexcept; void OnDisplayChange(DisplayChangeType changeType) noexcept;
void AddWorkArea(HMONITOR monitor, const std::wstring& deviceId) noexcept; void AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& id) noexcept;
protected: protected:
static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept; static LRESULT CALLBACK s_WndProc(HWND, UINT, WPARAM, LPARAM) noexcept;
@@ -250,6 +250,22 @@ FancyZones::Run() noexcept
} }
} }
// Initialize COM. Needed for WMI monitor identifying
HRESULT comInitHres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(comInitHres))
{
Logger::error(L"Failed to initialize COM library. {}", get_last_error_or_default(comInitHres));
return;
}
// Initialize security. Needed for WMI monitor identifying
HRESULT comSecurityInitHres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (FAILED(comSecurityInitHres))
{
Logger::error(L"Failed to initialize security. {}", get_last_error_or_default(comSecurityInitHres));
return;
}
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [] { m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [] {
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE); SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR_MIXED); SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR_MIXED);
@@ -278,6 +294,8 @@ FancyZones::Destroy() noexcept
DestroyWindow(m_window); DestroyWindow(m_window);
m_window = nullptr; m_window = nullptr;
} }
CoUninitialize();
} }
// IFancyZonesCallback // IFancyZonesCallback
@@ -674,6 +692,11 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
if (changeType == DisplayChangeType::Initialization) if (changeType == DisplayChangeType::Initialization)
{ {
RegisterVirtualDesktopUpdates(); RegisterVirtualDesktopUpdates();
// id format of applied-layouts and app-zone-history was changed in 0.60
auto monitors = MonitorUtils::IdentifyMonitors();
AppliedLayouts::instance().AdjustWorkAreaIds(monitors);
AppZoneHistory::instance().AdjustWorkAreaIds(monitors);
} }
} }
@@ -689,7 +712,7 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
} }
} }
void FancyZones::AddWorkArea(HMONITOR monitor, const std::wstring& deviceId) noexcept void FancyZones::AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& id) noexcept
{ {
if (m_workAreaHandler.IsNewWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), monitor)) if (m_workAreaHandler.IsNewWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), monitor))
{ {
@@ -699,26 +722,14 @@ void FancyZones::AddWorkArea(HMONITOR monitor, const std::wstring& deviceId) noe
Logger::debug(L"Add new work area on virtual desktop {}", virtualDesktopIdStr.get()); Logger::debug(L"Add new work area on virtual desktop {}", virtualDesktopIdStr.get());
} }
FancyZonesDataTypes::DeviceIdData uniqueId; FancyZonesDataTypes::WorkAreaId parentId{};
uniqueId.virtualDesktopId = VirtualDesktop::instance().GetCurrentVirtualDesktopId();
if (monitor)
{
uniqueId.deviceName = FancyZonesUtils::TrimDeviceId(deviceId);
}
else
{
uniqueId.deviceName = ZonedWindowProperties::MultiMonitorDeviceID;
}
FancyZonesDataTypes::DeviceIdData parentId{};
auto parentArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetPreviousVirtualDesktopId(), monitor); auto parentArea = m_workAreaHandler.GetWorkArea(VirtualDesktop::instance().GetPreviousVirtualDesktopId(), monitor);
if (parentArea) if (parentArea)
{ {
parentId = parentArea->UniqueId(); parentId = parentArea->UniqueId();
} }
auto workArea = MakeWorkArea(m_hinstance, monitor, uniqueId, parentId); auto workArea = MakeWorkArea(m_hinstance, monitor, id, parentId);
if (workArea) if (workArea)
{ {
m_workAreaHandler.AddWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), monitor, workArea); m_workAreaHandler.AddWorkArea(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), monitor, workArea);
@@ -745,34 +756,23 @@ void FancyZones::UpdateWorkAreas() noexcept
{ {
if (FancyZonesSettings::settings().spanZonesAcrossMonitors) if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
{ {
AddWorkArea(nullptr, {}); FancyZonesDataTypes::WorkAreaId workAreaId;
workAreaId.virtualDesktopId = VirtualDesktop::instance().GetCurrentVirtualDesktopId();
workAreaId.monitorId = { .deviceId = ZonedWindowProperties::MultiMonitorDeviceID };
AddWorkArea(nullptr, workAreaId);
} }
else else
{ {
// Mapping between display device name and device index (operating system identifies each display device with an index value). auto monitors = MonitorUtils::IdentifyMonitors();
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap; for (const auto& monitor : monitors)
struct capture
{ {
FancyZones* fancyZones; FancyZonesDataTypes::WorkAreaId workAreaId;
std::unordered_map<std::wstring, DWORD>* displayDeviceIdx; workAreaId.virtualDesktopId = VirtualDesktop::instance().GetCurrentVirtualDesktopId();
}; workAreaId.monitorId = monitor;
auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM data) -> BOOL { AddWorkArea(monitor.monitor, workAreaId);
capture* params = reinterpret_cast<capture*>(data); }
MONITORINFOEX mi{ { .cbSize = sizeof(mi) } };
if (GetMonitorInfoW(monitor, &mi))
{
auto& displayDeviceIdxMap = *(params->displayDeviceIdx);
FancyZones* fancyZones = params->fancyZones;
std::wstring deviceId = FancyZonesUtils::GetDisplayDeviceId(mi.szDevice, displayDeviceIdxMap);
fancyZones->AddWorkArea(monitor, deviceId);
}
return TRUE;
};
capture capture{ this, &displayDeviceIdxMap };
EnumDisplayMonitors(nullptr, nullptr, callback, reinterpret_cast<LPARAM>(&capture));
} }
} }

View File

@@ -8,6 +8,7 @@
#include <FancyZonesLib/GuidUtils.h> #include <FancyZonesLib/GuidUtils.h>
#include <FancyZonesLib/FancyZonesWindowProperties.h> #include <FancyZonesLib/FancyZonesWindowProperties.h>
#include <FancyZonesLib/JsonHelpers.h> #include <FancyZonesLib/JsonHelpers.h>
#include <FancyZonesLib/MonitorUtils.h>
#include <FancyZonesLib/VirtualDesktop.h> #include <FancyZonesLib/VirtualDesktop.h>
#include <FancyZonesLib/util.h> #include <FancyZonesLib/util.h>
@@ -16,7 +17,7 @@ namespace JsonUtils
struct AppZoneHistoryJSON struct AppZoneHistoryJSON
{ {
private: private:
static std::optional<FancyZonesDataTypes::DeviceIdData> DeviceIdFromJson(const json::JsonObject& json) static std::optional<FancyZonesDataTypes::WorkAreaId> DeviceIdFromJson(const json::JsonObject& json)
{ {
try try
{ {
@@ -24,6 +25,8 @@ namespace JsonUtils
{ {
json::JsonObject device = json.GetNamedObject(NonLocalizable::AppZoneHistoryIds::DeviceID); json::JsonObject device = json.GetNamedObject(NonLocalizable::AppZoneHistoryIds::DeviceID);
std::wstring monitor = device.GetNamedString(NonLocalizable::AppZoneHistoryIds::MonitorID).c_str(); std::wstring monitor = device.GetNamedString(NonLocalizable::AppZoneHistoryIds::MonitorID).c_str();
std::wstring monitorInstance = device.GetNamedString(NonLocalizable::AppZoneHistoryIds::MonitorInstanceID, L"").c_str();
std::wstring monitorSerialNumber = device.GetNamedString(NonLocalizable::AppZoneHistoryIds::MonitorSerialNumberID, L"").c_str();
std::wstring virtualDesktop = device.GetNamedString(NonLocalizable::AppZoneHistoryIds::VirtualDesktopID).c_str(); std::wstring virtualDesktop = device.GetNamedString(NonLocalizable::AppZoneHistoryIds::VirtualDesktopID).c_str();
auto virtualDesktopGuid = FancyZonesUtils::GuidFromString(virtualDesktop); auto virtualDesktopGuid = FancyZonesUtils::GuidFromString(virtualDesktop);
@@ -32,8 +35,25 @@ namespace JsonUtils
return std::nullopt; return std::nullopt;
} }
return FancyZonesDataTypes::DeviceIdData{ FancyZonesDataTypes::DeviceId deviceId{};
.deviceName = monitor, if (monitorInstance.empty())
{
// old data
deviceId = MonitorUtils::Display::ConvertObsoleteDeviceId(monitor);
}
else
{
deviceId.id = monitor;
deviceId.instanceId = monitorInstance;
}
FancyZonesDataTypes::MonitorId monitorId{
.deviceId = deviceId,
.serialNumber = monitorSerialNumber
};
return FancyZonesDataTypes::WorkAreaId{
.monitorId = monitorId,
.virtualDesktopId = virtualDesktopGuid.value(), .virtualDesktopId = virtualDesktopGuid.value(),
}; };
} }
@@ -46,8 +66,8 @@ namespace JsonUtils
return std::nullopt; return std::nullopt;
} }
return FancyZonesDataTypes::DeviceIdData{ return FancyZonesDataTypes::WorkAreaId{
.deviceName = bcDeviceId->deviceName, .monitorId = { .deviceId = MonitorUtils::Display::ConvertObsoleteDeviceId(bcDeviceId->deviceName) },
.virtualDesktopId = bcDeviceId->virtualDesktopId, .virtualDesktopId = bcDeviceId->virtualDesktopId,
}; };
} }
@@ -80,7 +100,7 @@ namespace JsonUtils
return std::nullopt; return std::nullopt;
} }
data.deviceId = deviceIdOpt.value(); data.workAreaId = deviceIdOpt.value();
data.zoneSetUuid = json.GetNamedString(NonLocalizable::AppZoneHistoryIds::LayoutIdID); data.zoneSetUuid = json.GetNamedString(NonLocalizable::AppZoneHistoryIds::LayoutIdID);
if (!FancyZonesUtils::IsValidGuid(data.zoneSetUuid)) if (!FancyZonesUtils::IsValidGuid(data.zoneSetUuid))
@@ -152,8 +172,11 @@ namespace JsonUtils
} }
json::JsonObject device{}; json::JsonObject device{};
device.SetNamedValue(NonLocalizable::AppZoneHistoryIds::MonitorID, json::value(data.deviceId.deviceName)); device.SetNamedValue(NonLocalizable::AppZoneHistoryIds::MonitorID, json::value(data.workAreaId.monitorId.deviceId.id));
auto virtualDesktopStr = FancyZonesUtils::GuidToString(data.deviceId.virtualDesktopId); device.SetNamedValue(NonLocalizable::AppZoneHistoryIds::MonitorInstanceID, json::value(data.workAreaId.monitorId.deviceId.instanceId));
device.SetNamedValue(NonLocalizable::AppZoneHistoryIds::MonitorSerialNumberID, json::value(data.workAreaId.monitorId.serialNumber));
auto virtualDesktopStr = FancyZonesUtils::GuidToString(data.workAreaId.virtualDesktopId);
if (virtualDesktopStr) if (virtualDesktopStr)
{ {
device.SetNamedValue(NonLocalizable::AppZoneHistoryIds::VirtualDesktopID, json::value(virtualDesktopStr.value())); device.SetNamedValue(NonLocalizable::AppZoneHistoryIds::VirtualDesktopID, json::value(virtualDesktopStr.value()));
@@ -255,9 +278,9 @@ void AppZoneHistory::SaveData()
auto updatedVector = dataVector; auto updatedVector = dataVector;
for (auto& data : updatedVector) for (auto& data : updatedVector)
{ {
if (!VirtualDesktop::instance().IsVirtualDesktopIdSavedInRegistry(data.deviceId.virtualDesktopId)) if (!VirtualDesktop::instance().IsVirtualDesktopIdSavedInRegistry(data.workAreaId.virtualDesktopId))
{ {
data.deviceId.virtualDesktopId = GUID_NULL; data.workAreaId.virtualDesktopId = GUID_NULL;
dirtyFlag = true; dirtyFlag = true;
} }
} }
@@ -275,9 +298,40 @@ void AppZoneHistory::SaveData()
} }
} }
bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet) void AppZoneHistory::AdjustWorkAreaIds(const std::vector<FancyZonesDataTypes::MonitorId>& ids)
{ {
if (IsAnotherWindowOfApplicationInstanceZoned(window, deviceId)) bool dirtyFlag = false;
for (auto iter = m_history.begin(); iter != m_history.end(); ++iter)
{
auto& [app, data] = *iter;
for (auto& dataIter = data.begin(); dataIter != data.end(); ++dataIter)
{
auto& dataMonitorId = dataIter->workAreaId.monitorId;
if (dataMonitorId.serialNumber.empty() && !dataMonitorId.deviceId.isDefault())
{
for (const auto& monitorId : ids)
{
if (dataMonitorId.deviceId.id == monitorId.deviceId.id && dataMonitorId.deviceId.instanceId == monitorId.deviceId.instanceId)
{
dataMonitorId.serialNumber = monitorId.serialNumber;
dirtyFlag = true;
break;
}
}
}
}
}
if (dirtyFlag)
{
SaveData();
}
}
bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet)
{
if (IsAnotherWindowOfApplicationInstanceZoned(window, workAreaId))
{ {
return false; return false;
} }
@@ -288,7 +342,7 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Dev
return false; return false;
} }
Logger::info(L"Add app zone history, device: {}, layout: {}", deviceId.toString(), zoneSetId); Logger::info(L"Add app zone history, device: {}, layout: {}", workAreaId.toString(), zoneSetId);
DWORD processId = 0; DWORD processId = 0;
GetWindowThreadProcessId(window, &processId); GetWindowThreadProcessId(window, &processId);
@@ -299,7 +353,7 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Dev
auto& perDesktopData = history->second; auto& perDesktopData = history->second;
for (auto& data : perDesktopData) for (auto& data : perDesktopData)
{ {
if (data.deviceId == deviceId) if (data.workAreaId == workAreaId)
{ {
// application already has history on this work area, update it with new window position // application already has history on this work area, update it with new window position
data.processIdToHandleMap[processId] = window; data.processIdToHandleMap[processId] = window;
@@ -315,7 +369,7 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Dev
processIdToHandleMap[processId] = window; processIdToHandleMap[processId] = window;
FancyZonesDataTypes::AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap, FancyZonesDataTypes::AppZoneHistoryData data{ .processIdToHandleMap = processIdToHandleMap,
.zoneSetUuid = zoneSetId, .zoneSetUuid = zoneSetId,
.deviceId = deviceId, .workAreaId = workAreaId,
.zoneIndexSet = zoneIndexSet }; .zoneIndexSet = zoneIndexSet };
if (m_history.contains(processPath)) if (m_history.contains(processPath))
@@ -333,9 +387,9 @@ bool AppZoneHistory::SetAppLastZones(HWND window, const FancyZonesDataTypes::Dev
return true; return true;
} }
bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring_view& zoneSetId)
{ {
Logger::info(L"Add app zone history, device: {}, layout: {}", deviceId.toString(), zoneSetId); Logger::info(L"Add app zone history, device: {}, layout: {}", workAreaId.toString(), zoneSetId);
auto processPath = get_process_path_waiting_uwp(window); auto processPath = get_process_path_waiting_uwp(window);
if (!processPath.empty()) if (!processPath.empty())
@@ -346,9 +400,9 @@ bool AppZoneHistory::RemoveAppLastZone(HWND window, const FancyZonesDataTypes::D
auto& perDesktopData = history->second; auto& perDesktopData = history->second;
for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);) for (auto data = std::begin(perDesktopData); data != std::end(perDesktopData);)
{ {
if (data->deviceId == deviceId && data->zoneSetUuid == zoneSetId) if (data->workAreaId == workAreaId && data->zoneSetUuid == zoneSetId)
{ {
if (!IsAnotherWindowOfApplicationInstanceZoned(window, deviceId)) if (!IsAnotherWindowOfApplicationInstanceZoned(window, workAreaId))
{ {
DWORD processId = 0; DWORD processId = 0;
GetWindowThreadProcessId(window, &processId); GetWindowThreadProcessId(window, &processId);
@@ -396,7 +450,7 @@ const AppZoneHistory::TAppZoneHistoryMap& AppZoneHistory::GetFullAppZoneHistory(
return m_history; return m_history;
} }
std::optional<FancyZonesDataTypes::AppZoneHistoryData> AppZoneHistory::GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept std::optional<FancyZonesDataTypes::AppZoneHistoryData> AppZoneHistory::GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept
{ {
auto app = appPath; auto app = appPath;
auto pos = appPath.find_last_of('\\'); auto pos = appPath.find_last_of('\\');
@@ -405,10 +459,10 @@ std::optional<FancyZonesDataTypes::AppZoneHistoryData> AppZoneHistory::GetZoneHi
app = appPath.substr(pos + 1); app = appPath.substr(pos + 1);
} }
auto srcVirtualDesktopIDStr = FancyZonesUtils::GuidToString(deviceId.virtualDesktopId); auto srcVirtualDesktopIDStr = FancyZonesUtils::GuidToString(workAreaId.virtualDesktopId);
if (srcVirtualDesktopIDStr) if (srcVirtualDesktopIDStr)
{ {
Logger::debug(L"Get {} zone history on monitor: {}, virtual desktop: {}", app, deviceId.deviceName, srcVirtualDesktopIDStr.value()); Logger::debug(L"Get {} zone history on monitor: {}, virtual desktop: {}", app, workAreaId.toString(), srcVirtualDesktopIDStr.value());
} }
auto iter = m_history.find(appPath); auto iter = m_history.find(appPath);
@@ -421,15 +475,15 @@ std::optional<FancyZonesDataTypes::AppZoneHistoryData> AppZoneHistory::GetZoneHi
auto historyVector = iter->second; auto historyVector = iter->second;
for (const auto& history : historyVector) for (const auto& history : historyVector)
{ {
if (history.deviceId.deviceName == deviceId.deviceName) if (history.workAreaId == workAreaId)
{ {
auto vdStr = FancyZonesUtils::GuidToString(history.deviceId.virtualDesktopId); auto vdStr = FancyZonesUtils::GuidToString(history.workAreaId.virtualDesktopId);
if (vdStr) if (vdStr)
{ {
Logger::debug(L"App zone history found on the device {} with virtual desktop {}", history.deviceId.deviceName, vdStr.value()); Logger::debug(L"App zone history found on the device {} with virtual desktop {}", history.workAreaId.toString(), vdStr.value());
} }
if (history.deviceId.virtualDesktopId == deviceId.virtualDesktopId || history.deviceId.virtualDesktopId == GUID_NULL) if (history.workAreaId.virtualDesktopId == workAreaId.virtualDesktopId || history.workAreaId.virtualDesktopId == GUID_NULL)
{ {
return history; return history;
} }
@@ -439,7 +493,7 @@ std::optional<FancyZonesDataTypes::AppZoneHistoryData> AppZoneHistory::GetZoneHi
return std::nullopt; return std::nullopt;
} }
bool AppZoneHistory::IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept bool AppZoneHistory::IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept
{ {
auto processPath = get_process_path_waiting_uwp(window); auto processPath = get_process_path_waiting_uwp(window);
if (!processPath.empty()) if (!processPath.empty())
@@ -450,7 +504,7 @@ bool AppZoneHistory::IsAnotherWindowOfApplicationInstanceZoned(HWND window, cons
auto& perDesktopData = history->second; auto& perDesktopData = history->second;
for (auto& data : perDesktopData) for (auto& data : perDesktopData)
{ {
if (data.deviceId == deviceId) if (data.workAreaId == workAreaId)
{ {
DWORD processId = 0; DWORD processId = 0;
GetWindowThreadProcessId(window, &processId); GetWindowThreadProcessId(window, &processId);
@@ -473,7 +527,7 @@ bool AppZoneHistory::IsAnotherWindowOfApplicationInstanceZoned(HWND window, cons
return false; return false;
} }
void AppZoneHistory::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) void AppZoneHistory::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId)
{ {
auto processPath = get_process_path_waiting_uwp(window); auto processPath = get_process_path_waiting_uwp(window);
if (!processPath.empty()) if (!processPath.empty())
@@ -484,7 +538,7 @@ void AppZoneHistory::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDat
auto& perDesktopData = history->second; auto& perDesktopData = history->second;
for (auto& data : perDesktopData) for (auto& data : perDesktopData)
{ {
if (data.deviceId == deviceId) if (data.workAreaId == workAreaId)
{ {
DWORD processId = 0; DWORD processId = 0;
GetWindowThreadProcessId(window, &processId); GetWindowThreadProcessId(window, &processId);
@@ -496,7 +550,7 @@ void AppZoneHistory::UpdateProcessIdToHandleMap(HWND window, const FancyZonesDat
} }
} }
ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring_view& zoneSetId) const
{ {
auto processPath = get_process_path_waiting_uwp(window); auto processPath = get_process_path_waiting_uwp(window);
if (processPath.empty()) if (processPath.empty())
@@ -505,7 +559,7 @@ ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZone
return {}; return {};
} }
auto srcVirtualDesktopIDStr = FancyZonesUtils::GuidToString(deviceId.virtualDesktopId); auto srcVirtualDesktopIDStr = FancyZonesUtils::GuidToString(workAreaId.virtualDesktopId);
auto app = processPath; auto app = processPath;
auto pos = processPath.find_last_of('\\'); auto pos = processPath.find_last_of('\\');
if (pos != std::string::npos && pos + 1 < processPath.length()) if (pos != std::string::npos && pos + 1 < processPath.length())
@@ -515,7 +569,7 @@ ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZone
if (srcVirtualDesktopIDStr) if (srcVirtualDesktopIDStr)
{ {
Logger::debug(L"Get {} zone history on monitor: {}, virtual desktop: {}", app, deviceId.deviceName, srcVirtualDesktopIDStr.value()); Logger::debug(L"Get {} zone history on monitor: {}, virtual desktop: {}", app, workAreaId.toString(), srcVirtualDesktopIDStr.value());
} }
auto history = m_history.find(processPath); auto history = m_history.find(processPath);
@@ -527,15 +581,15 @@ ZoneIndexSet AppZoneHistory::GetAppLastZoneIndexSet(HWND window, const FancyZone
const auto& perDesktopData = history->second; const auto& perDesktopData = history->second;
for (const auto& data : perDesktopData) for (const auto& data : perDesktopData)
{ {
if (data.zoneSetUuid == zoneSetId && data.deviceId.deviceName == deviceId.deviceName) if (data.zoneSetUuid == zoneSetId && data.workAreaId == workAreaId)
{ {
auto vdStr = FancyZonesUtils::GuidToString(data.deviceId.virtualDesktopId); auto vdStr = FancyZonesUtils::GuidToString(data.workAreaId.virtualDesktopId);
if (vdStr) if (vdStr)
{ {
Logger::debug(L"App zone history found on the device {} with virtual desktop {}", data.deviceId.deviceName, vdStr.value()); Logger::debug(L"App zone history found on the device {} with virtual desktop {}", data.workAreaId.toString(), vdStr.value());
} }
if (data.deviceId.virtualDesktopId == deviceId.virtualDesktopId || data.deviceId.virtualDesktopId == GUID_NULL) if (data.workAreaId.virtualDesktopId == workAreaId.virtualDesktopId || data.workAreaId.virtualDesktopId == GUID_NULL)
{ {
return data.zoneIndexSet; return data.zoneIndexSet;
} }
@@ -573,9 +627,9 @@ void AppZoneHistory::SyncVirtualDesktops()
{ {
for (auto& data : perDesktopData) for (auto& data : perDesktopData)
{ {
if (data.deviceId.virtualDesktopId == GUID_NULL) if (data.workAreaId.virtualDesktopId == GUID_NULL)
{ {
data.deviceId.virtualDesktopId = savedInRegistryVirtualDesktopID.value(); data.workAreaId.virtualDesktopId = savedInRegistryVirtualDesktopID.value();
dirtyFlag = true; dirtyFlag = true;
} }
} }
@@ -598,9 +652,9 @@ void AppZoneHistory::RemoveDeletedVirtualDesktops(const std::vector<GUID>& activ
auto& perDesktopData = it->second; auto& perDesktopData = it->second;
for (auto desktopIt = std::begin(perDesktopData); desktopIt != std::end(perDesktopData);) for (auto desktopIt = std::begin(perDesktopData); desktopIt != std::end(perDesktopData);)
{ {
if (desktopIt->deviceId.virtualDesktopId != GUID_NULL && !active.contains(desktopIt->deviceId.virtualDesktopId)) if (desktopIt->workAreaId.virtualDesktopId != GUID_NULL && !active.contains(desktopIt->workAreaId.virtualDesktopId))
{ {
auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(desktopIt->deviceId.virtualDesktopId); auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(desktopIt->workAreaId.virtualDesktopId);
if (virtualDesktopIdStr) if (virtualDesktopIdStr)
{ {
Logger::info(L"Remove Virtual Desktop id {} from app-zone-history", virtualDesktopIdStr.value()); Logger::info(L"Remove Virtual Desktop id {} from app-zone-history", virtualDesktopIdStr.value());

View File

@@ -17,6 +17,8 @@ namespace NonLocalizable
const static wchar_t* DeviceIdID = L"device-id"; const static wchar_t* DeviceIdID = L"device-id";
const static wchar_t* DeviceID = L"device"; const static wchar_t* DeviceID = L"device";
const static wchar_t* MonitorID = L"monitor"; const static wchar_t* MonitorID = L"monitor";
const static wchar_t* MonitorInstanceID = L"monitor-instance";
const static wchar_t* MonitorSerialNumberID = L"serial-number";
const static wchar_t* VirtualDesktopID = L"virtual-desktop"; const static wchar_t* VirtualDesktopID = L"virtual-desktop";
} }
} }
@@ -39,18 +41,19 @@ public:
void LoadData(); void LoadData();
void SaveData(); void SaveData();
void AdjustWorkAreaIds(const std::vector<FancyZonesDataTypes::MonitorId>& ids);
bool SetAppLastZones(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet); bool SetAppLastZones(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring& zoneSetId, const ZoneIndexSet& zoneIndexSet);
bool RemoveAppLastZone(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId); bool RemoveAppLastZone(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring_view& zoneSetId);
void RemoveApp(const std::wstring& appPath); void RemoveApp(const std::wstring& appPath);
const TAppZoneHistoryMap& GetFullAppZoneHistory() const noexcept; const TAppZoneHistoryMap& GetFullAppZoneHistory() const noexcept;
std::optional<FancyZonesDataTypes::AppZoneHistoryData> GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept; std::optional<FancyZonesDataTypes::AppZoneHistoryData> GetZoneHistory(const std::wstring& appPath, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept;
bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId) const noexcept; bool IsAnotherWindowOfApplicationInstanceZoned(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId) const noexcept;
void UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId); void UpdateProcessIdToHandleMap(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId);
ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::DeviceIdData& deviceId, const std::wstring_view& zoneSetId) const; ZoneIndexSet GetAppLastZoneIndexSet(HWND window, const FancyZonesDataTypes::WorkAreaId& workAreaId, const std::wstring_view& zoneSetId) const;
void SyncVirtualDesktops(); void SyncVirtualDesktops();
void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops); void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops);

View File

@@ -9,6 +9,7 @@
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h> #include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
#include <FancyZonesLib/FancyZonesWinHookEventIDs.h> #include <FancyZonesLib/FancyZonesWinHookEventIDs.h>
#include <FancyZonesLib/JsonHelpers.h> #include <FancyZonesLib/JsonHelpers.h>
#include <FancyZonesLib/MonitorUtils.h>
#include <FancyZonesLib/VirtualDesktop.h> #include <FancyZonesLib/VirtualDesktop.h>
#include <FancyZonesLib/util.h> #include <FancyZonesLib/util.h>
@@ -72,7 +73,7 @@ namespace JsonUtils
struct AppliedLayoutsJSON struct AppliedLayoutsJSON
{ {
private: private:
static std::optional<FancyZonesDataTypes::DeviceIdData> DeviceIdFromJson(const json::JsonObject& json) static std::optional<FancyZonesDataTypes::WorkAreaId> WorkAreaIdFromJson(const json::JsonObject& json)
{ {
try try
{ {
@@ -80,6 +81,8 @@ namespace JsonUtils
{ {
json::JsonObject device = json.GetNamedObject(NonLocalizable::AppliedLayoutsIds::DeviceID); json::JsonObject device = json.GetNamedObject(NonLocalizable::AppliedLayoutsIds::DeviceID);
std::wstring monitor = device.GetNamedString(NonLocalizable::AppliedLayoutsIds::MonitorID).c_str(); std::wstring monitor = device.GetNamedString(NonLocalizable::AppliedLayoutsIds::MonitorID).c_str();
std::wstring monitorInstance = device.GetNamedString(NonLocalizable::AppliedLayoutsIds::MonitorInstanceID, L"").c_str();
std::wstring monitorSerialNumber = device.GetNamedString(NonLocalizable::AppliedLayoutsIds::MonitorSerialNumberID, L"").c_str();
std::wstring virtualDesktop = device.GetNamedString(NonLocalizable::AppliedLayoutsIds::VirtualDesktopID).c_str(); std::wstring virtualDesktop = device.GetNamedString(NonLocalizable::AppliedLayoutsIds::VirtualDesktopID).c_str();
auto virtualDesktopGuid = FancyZonesUtils::GuidFromString(virtualDesktop); auto virtualDesktopGuid = FancyZonesUtils::GuidFromString(virtualDesktop);
@@ -88,8 +91,25 @@ namespace JsonUtils
return std::nullopt; return std::nullopt;
} }
return FancyZonesDataTypes::DeviceIdData{ FancyZonesDataTypes::DeviceId deviceId{};
.deviceName = monitor, if (monitorInstance.empty())
{
// old data
deviceId = MonitorUtils::Display::ConvertObsoleteDeviceId(monitor);
}
else
{
deviceId.id = monitor;
deviceId.instanceId = monitorInstance;
}
FancyZonesDataTypes::MonitorId monitorId{
.deviceId = deviceId,
.serialNumber = monitorSerialNumber
};
return FancyZonesDataTypes::WorkAreaId{
.monitorId = monitorId,
.virtualDesktopId = virtualDesktopGuid.value(), .virtualDesktopId = virtualDesktopGuid.value(),
}; };
} }
@@ -102,8 +122,8 @@ namespace JsonUtils
return std::nullopt; return std::nullopt;
} }
return FancyZonesDataTypes::DeviceIdData{ return FancyZonesDataTypes::WorkAreaId{
.deviceName = bcDeviceId->deviceName, .monitorId = { .deviceId = MonitorUtils::Display::ConvertObsoleteDeviceId(bcDeviceId->deviceName) },
.virtualDesktopId = bcDeviceId->virtualDesktopId, .virtualDesktopId = bcDeviceId->virtualDesktopId,
}; };
} }
@@ -115,7 +135,7 @@ namespace JsonUtils
} }
public: public:
FancyZonesDataTypes::DeviceIdData deviceId; FancyZonesDataTypes::WorkAreaId workAreaId;
Layout data; Layout data;
static std::optional<AppliedLayoutsJSON> FromJson(const json::JsonObject& json) static std::optional<AppliedLayoutsJSON> FromJson(const json::JsonObject& json)
@@ -124,7 +144,7 @@ namespace JsonUtils
{ {
AppliedLayoutsJSON result; AppliedLayoutsJSON result;
auto deviceIdOpt = DeviceIdFromJson(json); auto deviceIdOpt = WorkAreaIdFromJson(json);
if (!deviceIdOpt.has_value()) if (!deviceIdOpt.has_value())
{ {
return std::nullopt; return std::nullopt;
@@ -136,7 +156,7 @@ namespace JsonUtils
return std::nullopt; return std::nullopt;
} }
result.deviceId = std::move(deviceIdOpt.value()); result.workAreaId = std::move(deviceIdOpt.value());
result.data = std::move(layout.value()); result.data = std::move(layout.value());
return result; return result;
} }
@@ -149,9 +169,11 @@ namespace JsonUtils
static json::JsonObject ToJson(const AppliedLayoutsJSON& value) static json::JsonObject ToJson(const AppliedLayoutsJSON& value)
{ {
json::JsonObject device{}; json::JsonObject device{};
device.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorID, json::value(value.deviceId.deviceName)); device.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorID, json::value(value.workAreaId.monitorId.deviceId.id));
device.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorInstanceID, json::value(value.workAreaId.monitorId.deviceId.instanceId));
device.SetNamedValue(NonLocalizable::AppliedLayoutsIds::MonitorSerialNumberID, json::value(value.workAreaId.monitorId.serialNumber));
auto virtualDesktopStr = FancyZonesUtils::GuidToString(value.deviceId.virtualDesktopId); auto virtualDesktopStr = FancyZonesUtils::GuidToString(value.workAreaId.virtualDesktopId);
if (virtualDesktopStr) if (virtualDesktopStr)
{ {
device.SetNamedValue(NonLocalizable::AppliedLayoutsIds::VirtualDesktopID, json::value(virtualDesktopStr.value())); device.SetNamedValue(NonLocalizable::AppliedLayoutsIds::VirtualDesktopID, json::value(virtualDesktopStr.value()));
@@ -176,9 +198,9 @@ namespace JsonUtils
{ {
// skip default layouts in case if they were applied to different resolutions on the same monitor. // skip default layouts in case if they were applied to different resolutions on the same monitor.
// NOTE: keep the default layout check for users who update PT version from the v0.57 // NOTE: keep the default layout check for users who update PT version from the v0.57
if (!map.contains(obj->deviceId) && !isLayoutDefault(obj->data)) if (!map.contains(obj->workAreaId) && !isLayoutDefault(obj->data))
{ {
map[obj->deviceId] = std::move(obj->data); map[obj->workAreaId] = std::move(obj->data);
} }
} }
} }
@@ -194,7 +216,7 @@ namespace JsonUtils
for (const auto& [id, data] : map) for (const auto& [id, data] : map)
{ {
AppliedLayoutsJSON obj{}; AppliedLayoutsJSON obj{};
obj.deviceId = id; obj.workAreaId = id;
obj.data = data; obj.data = data;
layoutArray.Append(AppliedLayoutsJSON::ToJson(obj)); layoutArray.Append(AppliedLayoutsJSON::ToJson(obj));
} }
@@ -268,6 +290,41 @@ void AppliedLayouts::SaveData()
} }
} }
void AppliedLayouts::AdjustWorkAreaIds(const std::vector<FancyZonesDataTypes::MonitorId>& ids)
{
bool dirtyFlag = false;
std::vector<std::pair<FancyZonesDataTypes::WorkAreaId, std::wstring>> replaceWithSerialNumber{};
for (auto iter = m_layouts.begin(); iter != m_layouts.end(); ++iter)
{
const auto& [id, layout] = *iter;
if (id.monitorId.serialNumber.empty() && !id.monitorId.deviceId.isDefault())
{
for (const auto& monitorId : ids)
{
if (id.monitorId.deviceId.id == monitorId.deviceId.id && id.monitorId.deviceId.instanceId == monitorId.deviceId.instanceId)
{
replaceWithSerialNumber.push_back({ id, monitorId.serialNumber });
dirtyFlag = true;
break;
}
}
}
}
for (const auto& id : replaceWithSerialNumber)
{
auto mapEntry = m_layouts.extract(id.first);
mapEntry.key().monitorId.serialNumber = id.second;
m_layouts.insert(std::move(mapEntry));
}
if (dirtyFlag)
{
SaveData();
}
}
void AppliedLayouts::SyncVirtualDesktops() void AppliedLayouts::SyncVirtualDesktops()
{ {
// Explorer persists current virtual desktop identifier to registry on a per session basis, // Explorer persists current virtual desktop identifier to registry on a per session basis,
@@ -292,7 +349,7 @@ void AppliedLayouts::SyncVirtualDesktops()
bool dirtyFlag = false; bool dirtyFlag = false;
std::vector<FancyZonesDataTypes::DeviceIdData> replaceWithCurrentId{}; std::vector<FancyZonesDataTypes::WorkAreaId> replaceWithCurrentId{};
for (const auto& [id, data] : m_layouts) for (const auto& [id, data] : m_layouts)
{ {
@@ -351,7 +408,7 @@ void AppliedLayouts::RemoveDeletedVirtualDesktops(const std::vector<GUID>& activ
} }
} }
std::optional<Layout> AppliedLayouts::GetDeviceLayout(const FancyZonesDataTypes::DeviceIdData& id) const noexcept std::optional<Layout> AppliedLayouts::GetDeviceLayout(const FancyZonesDataTypes::WorkAreaId& id) const noexcept
{ {
auto iter = m_layouts.find(id); auto iter = m_layouts.find(id);
if (iter != m_layouts.end()) if (iter != m_layouts.end())
@@ -367,19 +424,19 @@ const AppliedLayouts::TAppliedLayoutsMap& AppliedLayouts::GetAppliedLayoutMap()
return m_layouts; return m_layouts;
} }
bool AppliedLayouts::IsLayoutApplied(const FancyZonesDataTypes::DeviceIdData& id) const noexcept bool AppliedLayouts::IsLayoutApplied(const FancyZonesDataTypes::WorkAreaId& id) const noexcept
{ {
auto iter = m_layouts.find(id); auto iter = m_layouts.find(id);
return iter != m_layouts.end(); return iter != m_layouts.end();
} }
bool AppliedLayouts::ApplyLayout(const FancyZonesDataTypes::DeviceIdData& deviceId, Layout layout) bool AppliedLayouts::ApplyLayout(const FancyZonesDataTypes::WorkAreaId& deviceId, Layout layout)
{ {
m_layouts[deviceId] = std::move(layout); m_layouts[deviceId] = std::move(layout);
return true; return true;
} }
bool AppliedLayouts::ApplyDefaultLayout(const FancyZonesDataTypes::DeviceIdData& deviceId) bool AppliedLayouts::ApplyDefaultLayout(const FancyZonesDataTypes::WorkAreaId& deviceId)
{ {
Logger::info(L"Set default layout on {}", deviceId.toString()); Logger::info(L"Set default layout on {}", deviceId.toString());
@@ -408,7 +465,7 @@ bool AppliedLayouts::ApplyDefaultLayout(const FancyZonesDataTypes::DeviceIdData&
return true; return true;
} }
bool AppliedLayouts::CloneLayout(const FancyZonesDataTypes::DeviceIdData& srcId, const FancyZonesDataTypes::DeviceIdData& dstId) bool AppliedLayouts::CloneLayout(const FancyZonesDataTypes::WorkAreaId& srcId, const FancyZonesDataTypes::WorkAreaId& dstId)
{ {
if (srcId == dstId || m_layouts.find(srcId) == m_layouts.end()) if (srcId == dstId || m_layouts.find(srcId) == m_layouts.end())
{ {

View File

@@ -18,6 +18,8 @@ namespace NonLocalizable
const static wchar_t* DeviceIdID = L"device-id"; const static wchar_t* DeviceIdID = L"device-id";
const static wchar_t* DeviceID = L"device"; const static wchar_t* DeviceID = L"device";
const static wchar_t* MonitorID = L"monitor"; const static wchar_t* MonitorID = L"monitor";
const static wchar_t* MonitorInstanceID = L"monitor-instance";
const static wchar_t* MonitorSerialNumberID = L"serial-number";
const static wchar_t* VirtualDesktopID = L"virtual-desktop"; const static wchar_t* VirtualDesktopID = L"virtual-desktop";
const static wchar_t* AppliedLayoutID = L"applied-layout"; const static wchar_t* AppliedLayoutID = L"applied-layout";
const static wchar_t* UuidID = L"uuid"; const static wchar_t* UuidID = L"uuid";
@@ -32,7 +34,7 @@ namespace NonLocalizable
class AppliedLayouts class AppliedLayouts
{ {
public: public:
using TAppliedLayoutsMap = std::unordered_map<FancyZonesDataTypes::DeviceIdData, Layout>; using TAppliedLayoutsMap = std::unordered_map<FancyZonesDataTypes::WorkAreaId, Layout>;
static AppliedLayouts& instance(); static AppliedLayouts& instance();
@@ -47,18 +49,19 @@ public:
void LoadData(); void LoadData();
void SaveData(); void SaveData();
void AdjustWorkAreaIds(const std::vector<FancyZonesDataTypes::MonitorId>& ids);
void SyncVirtualDesktops(); void SyncVirtualDesktops();
void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops); void RemoveDeletedVirtualDesktops(const std::vector<GUID>& activeDesktops);
std::optional<Layout> GetDeviceLayout(const FancyZonesDataTypes::DeviceIdData& id) const noexcept; std::optional<Layout> GetDeviceLayout(const FancyZonesDataTypes::WorkAreaId& id) const noexcept;
const TAppliedLayoutsMap& GetAppliedLayoutMap() const noexcept; const TAppliedLayoutsMap& GetAppliedLayoutMap() const noexcept;
bool IsLayoutApplied(const FancyZonesDataTypes::DeviceIdData& id) const noexcept; bool IsLayoutApplied(const FancyZonesDataTypes::WorkAreaId& id) const noexcept;
bool ApplyLayout(const FancyZonesDataTypes::DeviceIdData& deviceId, Layout layout); bool ApplyLayout(const FancyZonesDataTypes::WorkAreaId& deviceId, Layout layout);
bool ApplyDefaultLayout(const FancyZonesDataTypes::DeviceIdData& deviceId); bool ApplyDefaultLayout(const FancyZonesDataTypes::WorkAreaId& deviceId);
bool CloneLayout(const FancyZonesDataTypes::DeviceIdData& srcId, const FancyZonesDataTypes::DeviceIdData& dstId); bool CloneLayout(const FancyZonesDataTypes::WorkAreaId& srcId, const FancyZonesDataTypes::WorkAreaId& dstId);
private: private:
AppliedLayouts(); AppliedLayouts();

View File

@@ -128,8 +128,24 @@ namespace FancyZonesDataTypes
return high + 1; return high + 1;
} }
std::wstring DeviceId::toString() const noexcept
{
return id + L"_" + instanceId;
}
std::wstring DeviceIdData::toString() const bool DeviceId::isDefault() const noexcept
{
static const std::wstring defaultMonitorId = L"Default_Monitor";
return id == defaultMonitorId;
}
std::wstring MonitorId::toString() const noexcept
{
return deviceId.toString() + L"_" + serialNumber;
}
std::wstring WorkAreaId::toString() const noexcept
{ {
wil::unique_cotaskmem_string virtualDesktopIdStr; wil::unique_cotaskmem_string virtualDesktopIdStr;
if (!SUCCEEDED(StringFromCLSID(virtualDesktopId, &virtualDesktopIdStr))) if (!SUCCEEDED(StringFromCLSID(virtualDesktopId, &virtualDesktopIdStr)))
@@ -137,7 +153,7 @@ namespace FancyZonesDataTypes
return std::wstring(); return std::wstring();
} }
std::wstring result = deviceName + L"_" + virtualDesktopIdStr.get(); std::wstring result = monitorId.toString() + L"_" + virtualDesktopIdStr.get();
return result; return result;
} }

View File

@@ -113,20 +113,38 @@ namespace FancyZonesDataTypes
ZoneSetLayoutType type; ZoneSetLayoutType type;
}; };
struct DeviceIdData struct DeviceId
{ {
std::wstring deviceName = L"FallbackDevice"; std::wstring id;
std::wstring instanceId;
bool isDefault() const noexcept;
std::wstring toString() const noexcept;
};
struct MonitorId
{
HMONITOR monitor;
DeviceId deviceId;
std::wstring serialNumber;
std::wstring toString() const noexcept;
};
struct WorkAreaId
{
MonitorId monitorId;
GUID virtualDesktopId; GUID virtualDesktopId;
std::wstring toString() const; std::wstring toString() const noexcept;
}; };
struct AppZoneHistoryData struct AppZoneHistoryData
{ {
std::unordered_map<DWORD, HWND> processIdToHandleMap; // Maps process id(DWORD) of application to zoned window handle(HWND) std::unordered_map<DWORD, HWND> processIdToHandleMap; // Maps process id(DWORD) of application to zoned window handle(HWND)
std::wstring zoneSetUuid; std::wstring zoneSetUuid;
DeviceIdData deviceId; WorkAreaId workAreaId;
ZoneIndexSet zoneIndexSet; ZoneIndexSet zoneIndexSet;
}; };
@@ -144,33 +162,86 @@ namespace FancyZonesDataTypes
return lhs.type == rhs.type && lhs.uuid == rhs.uuid; return lhs.type == rhs.type && lhs.uuid == rhs.uuid;
} }
inline bool operator==(const DeviceIdData& lhs, const DeviceIdData& rhs)
{
return lhs.deviceName.compare(rhs.deviceName) == 0 && (lhs.virtualDesktopId == rhs.virtualDesktopId || lhs.virtualDesktopId == GUID_NULL || rhs.virtualDesktopId == GUID_NULL);
}
inline bool operator!=(const DeviceIdData& lhs, const DeviceIdData& rhs)
{
return !(lhs == rhs);
}
inline bool operator<(const DeviceIdData& lhs, const DeviceIdData& rhs)
{
return lhs.deviceName.compare(rhs.deviceName) < 0;
}
inline bool operator==(const DeviceInfoData& lhs, const DeviceInfoData& rhs) inline bool operator==(const DeviceInfoData& lhs, const DeviceInfoData& rhs)
{ {
return lhs.activeZoneSet == rhs.activeZoneSet && lhs.showSpacing == rhs.showSpacing && lhs.spacing == rhs.spacing && lhs.zoneCount == rhs.zoneCount && lhs.sensitivityRadius == rhs.sensitivityRadius; return lhs.activeZoneSet == rhs.activeZoneSet && lhs.showSpacing == rhs.showSpacing && lhs.spacing == rhs.spacing && lhs.zoneCount == rhs.zoneCount && lhs.sensitivityRadius == rhs.sensitivityRadius;
} }
inline bool operator==(const DeviceId& lhs, const DeviceId& rhs)
{
if (lhs.isDefault())
{
return lhs.instanceId == rhs.instanceId;
}
return lhs.id == rhs.id;
}
inline bool operator<(const DeviceId& lhs, const DeviceId& rhs)
{
return lhs.id < rhs.id || lhs.instanceId < rhs.instanceId;
}
inline bool operator==(const MonitorId& lhs, const MonitorId& rhs)
{
if (lhs.monitor && rhs.monitor)
{
return lhs.monitor == rhs.monitor;
}
if (!lhs.serialNumber.empty() || !rhs.serialNumber.empty())
{
bool serialNumbersEqual = lhs.serialNumber == rhs.serialNumber;
if (!serialNumbersEqual)
{
return false;
}
}
return lhs.deviceId == rhs.deviceId;
}
inline bool operator==(const WorkAreaId& lhs, const WorkAreaId& rhs)
{
bool vdEqual = (lhs.virtualDesktopId == rhs.virtualDesktopId || lhs.virtualDesktopId == GUID_NULL || rhs.virtualDesktopId == GUID_NULL);
return vdEqual && lhs.monitorId == rhs.monitorId;
}
inline bool operator!=(const WorkAreaId& lhs, const WorkAreaId& rhs)
{
bool vdEqual = (lhs.virtualDesktopId == rhs.virtualDesktopId || lhs.virtualDesktopId == GUID_NULL || rhs.virtualDesktopId == GUID_NULL);
return !vdEqual || lhs.monitorId != rhs.monitorId;
}
inline bool operator<(const WorkAreaId& lhs, const WorkAreaId& rhs)
{
if (lhs.monitorId.monitor && rhs.monitorId.monitor)
{
return lhs.monitorId.monitor < rhs.monitorId.monitor;
}
if (lhs.virtualDesktopId != GUID_NULL || rhs.virtualDesktopId != GUID_NULL)
{
return lhs.virtualDesktopId.Data1 < rhs.virtualDesktopId.Data1 ||
lhs.virtualDesktopId.Data2 < rhs.virtualDesktopId.Data2 ||
lhs.virtualDesktopId.Data3 < rhs.virtualDesktopId.Data3;
}
if (!lhs.monitorId.serialNumber.empty() || rhs.monitorId.serialNumber.empty())
{
return lhs.monitorId.serialNumber < rhs.monitorId.serialNumber;
}
return lhs.monitorId.deviceId < rhs.monitorId.deviceId;
}
} }
namespace std namespace std
{ {
template<> template<>
struct hash<FancyZonesDataTypes::DeviceIdData> struct hash<FancyZonesDataTypes::WorkAreaId>
{ {
size_t operator()(const FancyZonesDataTypes::DeviceIdData& Value) const size_t operator()(const FancyZonesDataTypes::WorkAreaId& Value) const
{ {
return 0; return 0;
} }

View File

@@ -10,6 +10,7 @@
#include <FancyZonesLib/FancyZonesData/LayoutDefaults.h> #include <FancyZonesLib/FancyZonesData/LayoutDefaults.h>
#include <FancyZonesLib/FancyZonesData/LayoutHotkeys.h> #include <FancyZonesLib/FancyZonesData/LayoutHotkeys.h>
#include <FancyZonesLib/FancyZonesData/LayoutTemplates.h> #include <FancyZonesLib/FancyZonesData/LayoutTemplates.h>
#include <FancyZonesLib/MonitorUtils.h>
#include <common/logger/logger.h> #include <common/logger/logger.h>
@@ -272,8 +273,8 @@ namespace
return std::nullopt; return std::nullopt;
} }
data.deviceId = FancyZonesDataTypes::DeviceIdData{ data.workAreaId = FancyZonesDataTypes::WorkAreaId{
.deviceName = deviceId->deviceName, .monitorId = { .deviceId = MonitorUtils::Display::ConvertObsoleteDeviceId(deviceId->deviceName) },
.virtualDesktopId = deviceId->virtualDesktopId .virtualDesktopId = deviceId->virtualDesktopId
}; };
data.zoneSetUuid = json.GetNamedString(NonLocalizable::ZoneSetUuidStr); data.zoneSetUuid = json.GetNamedString(NonLocalizable::ZoneSetUuidStr);

View File

@@ -1,49 +1,280 @@
#include "pch.h" #include "pch.h"
#include "MonitorUtils.h" #include "MonitorUtils.h"
#include <WbemCli.h>
#include <comutil.h>
#include <FancyZonesLib/WindowUtils.h> #include <FancyZonesLib/WindowUtils.h>
#include <FancyZonesLib/util.h>
#include <common/logger/logger.h>
#include <common/utils/winapi_error.h>
namespace MonitorUtils namespace MonitorUtils
{ {
constexpr int CUSTOM_POSITIONING_LEFT_TOP_PADDING = 16; constexpr int CUSTOM_POSITIONING_LEFT_TOP_PADDING = 16;
inline int RectWidth(const RECT& rect) namespace WMI
{ {
return rect.right - rect.left; FancyZonesDataTypes::DeviceId SplitWMIDeviceId(const std::wstring& str) noexcept
}
inline int RectHeight(const RECT& rect)
{
return rect.bottom - rect.top;
}
RECT FitOnScreen(const RECT& windowRect, const RECT& originMonitorRect, const RECT& destMonitorRect)
{
// New window position on active monitor. If window fits the screen, this will be final position.
int left = destMonitorRect.left + (windowRect.left - originMonitorRect.left);
int top = destMonitorRect.top + (windowRect.top - originMonitorRect.top);
int W = RectWidth(windowRect);
int H = RectHeight(windowRect);
if ((left < destMonitorRect.left) || (left + W > destMonitorRect.right))
{ {
// Set left window border to left border of screen (add padding). Resize window width if needed. // format: DISPLAY\{device id}\{instance id}
left = destMonitorRect.left + CUSTOM_POSITIONING_LEFT_TOP_PADDING; // example: DISPLAY\GSM0001\4&125707d6&0&UID28741_0
W = min(W, RectWidth(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING); // output: { GSM0001, 4&125707d6&0&UID28741 }
}
if ((top < destMonitorRect.top) || (top + H > destMonitorRect.bottom)) size_t nameStartPos = str.find_first_of('\\');
{ size_t uidStartPos = str.find_last_of('\\');
// Set top window border to top border of screen (add padding). Resize window height if needed. size_t uidEndPos = str.find_last_of('_');
top = destMonitorRect.top + CUSTOM_POSITIONING_LEFT_TOP_PADDING;
H = min(H, RectHeight(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING); if (nameStartPos == std::string::npos || uidStartPos == std::string::npos || uidEndPos == std::string::npos)
{
return { .id = str };
}
return { .id = str.substr(nameStartPos + 1, uidStartPos - nameStartPos - 1), .instanceId = str.substr(uidStartPos + 1, uidEndPos - uidStartPos - 1) };
} }
return { .left = left, std::wstring GetWMIProp(IWbemClassObject* wbemClassObj, std::wstring_view prop)
.top = top, {
.right = left + W, if (!wbemClassObj)
.bottom = top + H }; {
return {};
}
VARIANT vtProp{};
// Get the value of the Name property
auto hres = wbemClassObj->Get(prop.data(), 0, &vtProp, 0, 0);
if (FAILED(hres))
{
Logger::error(L"Get {} Error code = {} ", prop, get_last_error_or_default(hres));
return {};
}
std::wstring result{};
switch (vtProp.vt)
{
case VT_BSTR: //BSTR
{
result = vtProp.bstrVal;
}
break;
case VT_ARRAY: // parray
case 8195: // also parray
{
std::u32string str(static_cast<const char32_t*>(vtProp.parray->pvData));
std::wstring wstr;
for (const char32_t& c : str)
{
wstr += (wchar_t)c;
}
result = wstr;
}
break;
default:
break;
}
VariantClear(&vtProp);
return result;
}
std::vector<FancyZonesDataTypes::MonitorId> GetHardwareMonitorIds()
{
HRESULT hres;
// Obtain the initial locator to Windows Management
// on a particular host computer.
IWbemLocator* pLocator = 0;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLocator);
if (FAILED(hres))
{
Logger::error(L"Failed to create IWbemLocator object. {}", get_last_error_or_default(hres));
return {};
}
IWbemServices* pServices = 0;
hres = pLocator->ConnectServer(_bstr_t(L"ROOT\\WMI"), NULL, NULL, 0, NULL, 0, 0, &pServices);
if (FAILED(hres))
{
Logger::error(L"Could not connect WMI server. {}", get_last_error_or_default(hres));
pLocator->Release();
return {};
}
// Set the IWbemServices proxy so that impersonation
// of the user (client) occurs.
hres = CoSetProxyBlanket(pServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hres))
{
Logger::error(L"Could not set proxy blanket. {}", get_last_error_or_default(hres));
pServices->Release();
pLocator->Release();
return {};
}
// Use the IWbemServices pointer to make requests of WMI.
// Make requests here:
IEnumWbemClassObject* pEnumerator = NULL;
hres = pServices->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM WmiMonitorID"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
if (FAILED(hres))
{
Logger::error(L"Query for monitors failed. {}", get_last_error_or_default(hres));
pServices->Release();
pLocator->Release();
return {};
}
IWbemClassObject* pClassObject;
ULONG uReturn = 0;
std::vector<FancyZonesDataTypes::MonitorId> result{};
while (pEnumerator)
{
hres = pEnumerator->Next(WBEM_INFINITE, 1, &pClassObject, &uReturn);
if (0 == uReturn)
{
break;
}
LPSAFEARRAY pFieldArray = NULL;
hres = pClassObject->GetNames(NULL, WBEM_FLAG_ALWAYS, NULL, &pFieldArray);
if (FAILED(hres))
{
Logger::error(L"Failed to get field names. {}", get_last_error_or_default(hres));
break;
}
auto name = GetWMIProp(pClassObject, L"InstanceName");
FancyZonesDataTypes::MonitorId data{};
data.deviceId = SplitWMIDeviceId(name);
data.serialNumber = GetWMIProp(pClassObject, L"SerialNumberID");
Logger::info(L"InstanceName: {}", name);
Logger::info(L"Serial number: {}", data.serialNumber);
result.emplace_back(std::move(data));
pClassObject->Release();
pClassObject = NULL;
}
pServices->Release();
pLocator->Release();
pEnumerator->Release();
return result;
}
}
namespace Display
{
FancyZonesDataTypes::DeviceId SplitDisplayDeviceId(const std::wstring& str) noexcept
{
// format: \\?\DISPLAY#{device id}#{instance id}#{some other id}
// example: \\?\DISPLAY#GSM1388#4&125707d6&0&UID8388688#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
// output: { GSM1388, 4&125707d6&0&UID8388688 }
size_t nameStartPos = str.find_first_of('#');
size_t uidStartPos = str.find('#', nameStartPos + 1);
size_t uidEndPos = str.find('#', uidStartPos + 1);
if (nameStartPos == std::string::npos || uidStartPos == std::string::npos || uidEndPos == std::string::npos)
{
return { str, L"" };
}
return { .id = str.substr(nameStartPos + 1, uidStartPos - nameStartPos - 1), .instanceId = str.substr(uidStartPos + 1, uidEndPos - uidStartPos - 1) };
}
FancyZonesDataTypes::DeviceId ConvertObsoleteDeviceId(const std::wstring& str) noexcept
{
// format: {device id}#{instance id}
// example: GSM1388#4&125707d6&0&UID8388688
// output: { GSM1388, 4&125707d6&0&UID8388688 }
size_t dividerPos = str.find_first_of('#');
if (dividerPos == std::string::npos)
{
return { str, L"" };
}
return { .id = str.substr(0, dividerPos), .instanceId = str.substr(dividerPos + 1) };
}
std::vector<FancyZonesDataTypes::MonitorId> GetDisplays()
{
auto allMonitors = FancyZonesUtils::GetAllMonitorInfo<&MONITORINFOEX::rcWork>();
std::unordered_map<std::wstring, DWORD> displayDeviceIdxMap;
std::vector<FancyZonesDataTypes::MonitorId> result{};
for (auto& monitorData : allMonitors)
{
auto monitorInfo = monitorData.second;
DISPLAY_DEVICE displayDevice{ .cb = sizeof(displayDevice) };
std::wstring deviceId;
auto enumRes = EnumDisplayDevicesW(monitorInfo.szDevice, displayDeviceIdxMap[monitorInfo.szDevice], &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME);
if (!enumRes)
{
Logger::error(L"EnumDisplayDevicesW error: {}", get_last_error_or_default(GetLastError()));
continue;
}
Logger::info(L"Display: {}", displayDevice.DeviceID);
result.push_back({ .monitor = monitorData.first, .deviceId = SplitDisplayDeviceId(displayDevice.DeviceID) });
}
return result;
}
} }
namespace
{
inline int RectWidth(const RECT& rect)
{
return rect.right - rect.left;
}
inline int RectHeight(const RECT& rect)
{
return rect.bottom - rect.top;
}
RECT FitOnScreen(const RECT& windowRect, const RECT& originMonitorRect, const RECT& destMonitorRect)
{
// New window position on active monitor. If window fits the screen, this will be final position.
int left = destMonitorRect.left + (windowRect.left - originMonitorRect.left);
int top = destMonitorRect.top + (windowRect.top - originMonitorRect.top);
int W = RectWidth(windowRect);
int H = RectHeight(windowRect);
if ((left < destMonitorRect.left) || (left + W > destMonitorRect.right))
{
// Set left window border to left border of screen (add padding). Resize window width if needed.
left = destMonitorRect.left + CUSTOM_POSITIONING_LEFT_TOP_PADDING;
W = min(W, RectWidth(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING);
}
if ((top < destMonitorRect.top) || (top + H > destMonitorRect.bottom))
{
// Set top window border to top border of screen (add padding). Resize window height if needed.
top = destMonitorRect.top + CUSTOM_POSITIONING_LEFT_TOP_PADDING;
H = min(H, RectHeight(destMonitorRect) - CUSTOM_POSITIONING_LEFT_TOP_PADDING);
}
return { .left = left,
.top = top,
.right = left + W,
.bottom = top + H };
}
}
void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept
{ {
// By default Windows opens new window on primary monitor. // By default Windows opens new window on primary monitor.
@@ -73,4 +304,25 @@ namespace MonitorUtils
} }
} }
} }
std::vector<FancyZonesDataTypes::MonitorId> IdentifyMonitors() noexcept
{
Logger::info(L"Identifying monitors");
auto displays = Display::GetDisplays();
auto monitors = WMI::GetHardwareMonitorIds();
for (const auto& monitor : monitors)
{
for (auto& display : displays)
{
if (monitor.deviceId.id == display.deviceId.id)
{
display.serialNumber = monitor.serialNumber;
}
}
}
return displays;
}
} }

View File

@@ -1,6 +1,22 @@
#pragma once #pragma once
#include <FancyZonesLib/FancyZonesDataTypes.h>
namespace MonitorUtils namespace MonitorUtils
{ {
namespace Display
{
std::vector<FancyZonesDataTypes::MonitorId> GetDisplays();
FancyZonesDataTypes::DeviceId SplitDisplayDeviceId(const std::wstring& str) noexcept;
FancyZonesDataTypes::DeviceId ConvertObsoleteDeviceId(const std::wstring& str) noexcept;
}
namespace WMI
{
std::vector<FancyZonesDataTypes::MonitorId> GetHardwareMonitorIds();
FancyZonesDataTypes::DeviceId SplitWMIDeviceId(const std::wstring& str) noexcept;
}
std::vector<FancyZonesDataTypes::MonitorId> IdentifyMonitors() noexcept;
void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept; void OpenWindowOnActiveMonitor(HWND window, HMONITOR monitor) noexcept;
}; };

View File

@@ -120,7 +120,7 @@ WorkArea::~WorkArea()
windowPool.FreeZonesOverlayWindow(m_window); windowPool.FreeZonesOverlayWindow(m_window);
} }
bool WorkArea::Init(HINSTANCE hinstance, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId) bool WorkArea::Init(HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesDataTypes::WorkAreaId& parentUniqueId)
{ {
m_uniqueId = uniqueId; m_uniqueId = uniqueId;
InitializeZoneSets(parentUniqueId); InitializeZoneSets(parentUniqueId);
@@ -378,13 +378,9 @@ void WorkArea::FlashZones() noexcept
#pragma region private #pragma region private
void WorkArea::InitializeZoneSets(const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept void WorkArea::InitializeZoneSets(const FancyZonesDataTypes::WorkAreaId& parentUniqueId) noexcept
{ {
wil::unique_cotaskmem_string virtualDesktopId; Logger::info(L"Initialize layout on {}", m_uniqueId.toString());
if (SUCCEEDED(StringFromCLSID(m_uniqueId.virtualDesktopId, &virtualDesktopId)))
{
Logger::debug(L"Initialize layout on the virtual desktop {}", virtualDesktopId.get());
}
bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId); bool isLayoutAlreadyApplied = AppliedLayouts::instance().IsLayoutApplied(m_uniqueId);
if (!isLayoutAlreadyApplied) if (!isLayoutAlreadyApplied)

View File

@@ -13,7 +13,7 @@ public:
~WorkArea(); ~WorkArea();
public: public:
bool Init(HINSTANCE hinstance, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId); bool Init(HINSTANCE hinstance, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesDataTypes::WorkAreaId& parentUniqueId);
inline bool InitWorkAreaRect(HMONITOR monitor) inline bool InitWorkAreaRect(HMONITOR monitor)
{ {
m_monitor = monitor; m_monitor = monitor;
@@ -42,7 +42,7 @@ public:
return true; return true;
} }
FancyZonesDataTypes::DeviceIdData UniqueId() const noexcept { return { m_uniqueId }; } FancyZonesDataTypes::WorkAreaId UniqueId() const noexcept { return { m_uniqueId }; }
IZoneSet* ZoneSet() const noexcept { return m_zoneSet.get(); } IZoneSet* ZoneSet() const noexcept { return m_zoneSet.get(); }
ZoneIndexSet GetWindowZoneIndexes(HWND window) const noexcept; ZoneIndexSet GetWindowZoneIndexes(HWND window) const noexcept;
@@ -72,7 +72,7 @@ protected:
static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept; static LRESULT CALLBACK s_WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept;
private: private:
void InitializeZoneSets(const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept; void InitializeZoneSets(const FancyZonesDataTypes::WorkAreaId& parentUniqueId) noexcept;
void CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept; void CalculateZoneSet(OverlappingZonesAlgorithm overlappingAlgorithm) noexcept;
void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept; void UpdateActiveZoneSet(_In_opt_ IZoneSet* zoneSet) noexcept;
LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept; LRESULT WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexcept;
@@ -82,7 +82,7 @@ private:
HMONITOR m_monitor{}; HMONITOR m_monitor{};
FancyZonesUtils::Rect m_workAreaRect{}; FancyZonesUtils::Rect m_workAreaRect{};
FancyZonesDataTypes::DeviceIdData m_uniqueId; FancyZonesDataTypes::WorkAreaId m_uniqueId;
HWND m_window{}; // Hidden tool window used to represent current monitor desktop work area. HWND m_window{}; // Hidden tool window used to represent current monitor desktop work area.
HWND m_windowMoveSize{}; HWND m_windowMoveSize{};
winrt::com_ptr<IZoneSet> m_zoneSet; winrt::com_ptr<IZoneSet> m_zoneSet;
@@ -93,7 +93,7 @@ private:
std::unique_ptr<ZonesOverlay> m_zonesOverlay; std::unique_ptr<ZonesOverlay> m_zonesOverlay;
}; };
inline std::shared_ptr<WorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::DeviceIdData& uniqueId, const FancyZonesDataTypes::DeviceIdData& parentUniqueId) noexcept inline std::shared_ptr<WorkArea> MakeWorkArea(HINSTANCE hinstance, HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& uniqueId, const FancyZonesDataTypes::WorkAreaId& parentUniqueId) noexcept
{ {
auto self = std::make_shared<WorkArea>(hinstance); auto self = std::make_shared<WorkArea>(hinstance);
if (!self->InitWorkAreaRect(monitor)) if (!self->InitWorkAreaRect(monitor))

View File

@@ -16,63 +16,8 @@
namespace FancyZonesUtils namespace FancyZonesUtils
{ {
std::wstring TrimDeviceId(const std::wstring& deviceId)
{
// We're interested in the unique part between the first and last #'s
// Example input: \\?\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
// Example output: DELA026#5&10a58c63&0&UID16777488
static const std::wstring defaultDeviceId = L"FallbackDevice";
if (deviceId.empty())
{
return defaultDeviceId;
}
size_t start = deviceId.find(L'#');
size_t end = deviceId.rfind(L'#');
if (start != std::wstring::npos && end != std::wstring::npos && start != end)
{
size_t size = end - (start + 1);
return deviceId.substr(start + 1, size);
}
else
{
return defaultDeviceId;
}
}
typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*); typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*);
std::wstring GetDisplayDeviceId(const std::wstring& device, std::unordered_map<std::wstring, DWORD>& displayDeviceIdxMap)
{
DISPLAY_DEVICE displayDevice{ .cb = sizeof(displayDevice) };
std::wstring deviceId;
while (EnumDisplayDevicesW(device.c_str(), displayDeviceIdxMap[device], &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
++displayDeviceIdxMap[device];
Logger::info(L"Get display device: {}", displayDevice.DeviceID);
// Only take active monitors (presented as being "on" by the respective GDI view) and monitors that don't
// represent a pseudo device used to mirror application drawing.
if (WI_IsFlagSet(displayDevice.StateFlags, DISPLAY_DEVICE_ACTIVE) &&
WI_IsFlagClear(displayDevice.StateFlags, DISPLAY_DEVICE_MIRRORING_DRIVER))
{
deviceId = displayDevice.DeviceID;
break;
}
}
if (deviceId.empty())
{
Logger::info(L"Didn't find display device, set default");
deviceId = GetSystemMetrics(SM_REMOTESESSION) ?
L"\\\\?\\DISPLAY#REMOTEDISPLAY#" :
L"\\\\?\\DISPLAY#LOCALDISPLAY#";
}
return deviceId;
}
UINT GetDpiForMonitor(HMONITOR monitor) noexcept UINT GetDpiForMonitor(HMONITOR monitor) noexcept
{ {
UINT dpi{}; UINT dpi{};
@@ -206,37 +151,6 @@ namespace FancyZonesUtils
return std::nullopt; return std::nullopt;
} }
std::wstring GenerateUniqueId(HMONITOR monitor, const std::wstring& deviceId, const std::wstring& virtualDesktopId)
{
MONITORINFOEXW mi;
mi.cbSize = sizeof(mi);
if (!virtualDesktopId.empty() && GetMonitorInfo(monitor, &mi))
{
Rect const monitorRect(mi.rcMonitor);
// Unique identifier format: <parsed-device-id>_<width>_<height>_<virtual-desktop-id>
return TrimDeviceId(deviceId) +
L'_' +
virtualDesktopId;
}
return {};
}
std::wstring GenerateUniqueIdAllMonitorsArea(const std::wstring& virtualDesktopId)
{
std::wstring result{ ZonedWindowProperties::MultiMonitorDeviceID };
RECT combinedResolution = GetAllMonitorsCombinedRect<&MONITORINFO::rcMonitor>();
result += L'_';
result += std::to_wstring(combinedResolution.right - combinedResolution.left);
result += L'_';
result += std::to_wstring(combinedResolution.bottom - combinedResolution.top);
result += L'_';
result += virtualDesktopId;
return result;
}
size_t ChooseNextZoneByPosition(DWORD vkCode, RECT windowRect, const std::vector<RECT>& zoneRects) noexcept size_t ChooseNextZoneByPosition(DWORD vkCode, RECT windowRect, const std::vector<RECT>& zoneRects) noexcept
{ {
using complex = std::complex<double>; using complex = std::complex<double>;

View File

@@ -168,8 +168,6 @@ namespace FancyZonesUtils
return result; return result;
} }
std::wstring GetDisplayDeviceId(const std::wstring& device, std::unordered_map<std::wstring, DWORD>& displayDeviceIdxMap);
UINT GetDpiForMonitor(HMONITOR monitor) noexcept; UINT GetDpiForMonitor(HMONITOR monitor) noexcept;
void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo); void OrderMonitors(std::vector<std::pair<HMONITOR, RECT>>& monitorInfo);
@@ -177,10 +175,6 @@ namespace FancyZonesUtils
std::optional<GUID> GuidFromString(const std::wstring& str) noexcept; std::optional<GUID> GuidFromString(const std::wstring& str) noexcept;
std::optional<std::wstring> GuidToString(const GUID& guid) noexcept; std::optional<std::wstring> GuidToString(const GUID& guid) noexcept;
std::wstring GenerateUniqueId(HMONITOR monitor, const std::wstring& devideId, const std::wstring& virtualDesktopId);
std::wstring GenerateUniqueIdAllMonitorsArea(const std::wstring& virtualDesktopId);
std::wstring TrimDeviceId(const std::wstring& deviceId);
RECT PrepareRectForCycling(RECT windowRect, RECT workAreaRect, DWORD vkCode) noexcept; RECT PrepareRectForCycling(RECT windowRect, RECT workAreaRect, DWORD vkCode) noexcept;
size_t ChooseNextZoneByPosition(DWORD vkCode, RECT windowRect, const std::vector<RECT>& zoneRects) noexcept; size_t ChooseNextZoneByPosition(DWORD vkCode, RECT windowRect, const std::vector<RECT>& zoneRects) noexcept;
} }

View File

@@ -33,7 +33,7 @@
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>gdiplus.lib;dwmapi.lib;shlwapi.lib;uxtheme.lib;shcore.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>gdiplus.lib;dwmapi.lib;shlwapi.lib;uxtheme.lib;shcore.lib;wbemuuid.lib;comsuppw.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

View File

@@ -102,22 +102,22 @@ namespace FancyZonesUnitTests
Assert::AreEqual((size_t)2, AppZoneHistory::instance().GetFullAppZoneHistory().size()); Assert::AreEqual((size_t)2, AppZoneHistory::instance().GetFullAppZoneHistory().size());
{ {
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"monitor-1", .monitorId = { .deviceId = { .id = L"monitor-1" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{72FA9FC0-26A6-4B37-A834-491C148DFC58}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{72FA9FC0-26A6-4B37-A834-491C148DFC58}").value()
}; };
Assert::IsTrue(AppZoneHistory::instance().GetZoneHistory(L"app-1", id).has_value()); Assert::IsTrue(AppZoneHistory::instance().GetZoneHistory(L"app-1", id).has_value());
} }
{ {
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"monitor-2", .monitorId = { .deviceId = { .id = L"monitor-2" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{72FA9FC0-26A6-4B37-A834-491C148DFC58}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{72FA9FC0-26A6-4B37-A834-491C148DFC58}").value()
}; };
Assert::IsTrue(AppZoneHistory::instance().GetZoneHistory(L"app-1", id).has_value()); Assert::IsTrue(AppZoneHistory::instance().GetZoneHistory(L"app-1", id).has_value());
} }
{ {
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"monitor-1", .monitorId = { .deviceId = { .id = L"monitor-1" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{72FA9FC0-26A6-4B37-A834-491C148DFC58}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{72FA9FC0-26A6-4B37-A834-491C148DFC58}").value()
}; };
Assert::IsTrue(AppZoneHistory::instance().GetZoneHistory(L"app-2", id).has_value()); Assert::IsTrue(AppZoneHistory::instance().GetZoneHistory(L"app-2", id).has_value());
@@ -197,8 +197,8 @@ namespace FancyZonesUnitTests
Assert::AreEqual((size_t)1, AppZoneHistory::instance().GetFullAppZoneHistory().size()); Assert::AreEqual((size_t)1, AppZoneHistory::instance().GetFullAppZoneHistory().size());
{ {
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"monitor-1", .monitorId = { .deviceId = { .id = L"monitor-1" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{72FA9FC0-26A6-4B37-A834-491C148DFC58}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{72FA9FC0-26A6-4B37-A834-491C148DFC58}").value()
}; };
Assert::IsTrue(AppZoneHistory::instance().GetZoneHistory(L"app-1", id).has_value()); Assert::IsTrue(AppZoneHistory::instance().GetZoneHistory(L"app-1", id).has_value());
@@ -208,103 +208,136 @@ namespace FancyZonesUnitTests
TEST_METHOD (AppLastZoneInvalidWindow) TEST_METHOD (AppLastZoneInvalidWindow)
{ {
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaId{
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = Mocks::Window(); const auto window = Mocks::Window();
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId));
const int expectedZoneIndex = 1; const int expectedZoneIndex = 1;
Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetId, { expectedZoneIndex }));
} }
TEST_METHOD (AppLastZoneNullWindow) TEST_METHOD (AppLastZoneNullWindow)
{ {
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaId{
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = nullptr; const auto window = nullptr;
const int expectedZoneIndex = 1; const int expectedZoneIndex = 1;
Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetId, { expectedZoneIndex })); Assert::IsFalse(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetId, { expectedZoneIndex }));
} }
TEST_METHOD (AppLastdeviceIdTest) TEST_METHOD (AppLastdeviceIdTest)
{ {
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
const FancyZonesDataTypes::DeviceIdData deviceId1{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaId1{
const FancyZonesDataTypes::DeviceIdData deviceId2{ L"DELA026#5&10a58c63&0&UID16777489_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const FancyZonesDataTypes::WorkAreaId workAreaId2{
.monitorId = { .deviceId = { .id = L"DELA027", .instanceId = L"5&10a58c63&0&UID16777489" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = Mocks::WindowCreate(m_hInst); const auto window = Mocks::WindowCreate(m_hInst);
const int expectedZoneIndex = 10; const int expectedZoneIndex = 10;
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId1, zoneSetId, { expectedZoneIndex })); Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId1, zoneSetId, { expectedZoneIndex }));
Assert::IsTrue(std::vector<ZoneIndex>{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId1, zoneSetId)); Assert::IsTrue(std::vector<ZoneIndex>{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId1, zoneSetId));
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId2, zoneSetId)); Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId2, zoneSetId));
} }
TEST_METHOD (AppLastZoneSetIdTest) TEST_METHOD (AppLastZoneSetIdTest)
{ {
const std::wstring zoneSetId1 = L"{B7A1F5A9-9DC2-4505-84AB-993253839093}"; const std::wstring zoneSetId1 = L"{B7A1F5A9-9DC2-4505-84AB-993253839093}";
const std::wstring zoneSetId2 = L"{B7A1F5A9-9DC2-4505-84AB-993253839094}"; const std::wstring zoneSetId2 = L"{B7A1F5A9-9DC2-4505-84AB-993253839094}";
const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaId{
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = Mocks::WindowCreate(m_hInst); const auto window = Mocks::WindowCreate(m_hInst);
const int expectedZoneIndex = 10; const int expectedZoneIndex = 10;
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetId1, { expectedZoneIndex })); Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetId1, { expectedZoneIndex }));
Assert::IsTrue(std::vector<ZoneIndex>{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId1)); Assert::IsTrue(std::vector<ZoneIndex>{ expectedZoneIndex } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId1));
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId2)); Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId2));
} }
TEST_METHOD (AppLastZoneRemoveWindow) TEST_METHOD (AppLastZoneRemoveWindow)
{ {
const std::wstring zoneSetId = L"{B7A1F5A9-9DC2-4505-84AB-993253839093}"; const std::wstring zoneSetId = L"{B7A1F5A9-9DC2-4505-84AB-993253839093}";
const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaId{
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = Mocks::WindowCreate(m_hInst); const auto window = Mocks::WindowCreate(m_hInst);
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetId, { 1 })); Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetId, { 1 }));
Assert::IsTrue(AppZoneHistory::instance().RemoveAppLastZone(window, deviceId, zoneSetId)); Assert::IsTrue(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, zoneSetId));
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId));
} }
TEST_METHOD (AppLastZoneRemoveUnknownWindow) TEST_METHOD (AppLastZoneRemoveUnknownWindow)
{ {
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaId{
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = Mocks::WindowCreate(m_hInst); const auto window = Mocks::WindowCreate(m_hInst);
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, deviceId, zoneSetId)); Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, zoneSetId));
Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetId)); Assert::IsTrue(std::vector<ZoneIndex>{} == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetId));
} }
TEST_METHOD (AppLastZoneRemoveUnknownZoneSetId) TEST_METHOD (AppLastZoneRemoveUnknownZoneSetId)
{ {
const std::wstring zoneSetIdToInsert = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; const std::wstring zoneSetIdToInsert = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
const std::wstring zoneSetIdToRemove = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F1}"; const std::wstring zoneSetIdToRemove = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F1}";
const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaId{
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = Mocks::WindowCreate(m_hInst); const auto window = Mocks::WindowCreate(m_hInst);
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceId, zoneSetIdToInsert, { 1 })); Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaId, zoneSetIdToInsert, { 1 }));
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, deviceId, zoneSetIdToRemove)); Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaId, zoneSetIdToRemove));
Assert::IsTrue(std::vector<ZoneIndex>{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceId, zoneSetIdToInsert)); Assert::IsTrue(std::vector<ZoneIndex>{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaId, zoneSetIdToInsert));
} }
TEST_METHOD (AppLastZoneRemoveUnknownWindowId) TEST_METHOD (AppLastZoneRemoveUnknownWindowId)
{ {
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
const FancyZonesDataTypes::DeviceIdData deviceIdToInsert{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaIdToInsert{
const FancyZonesDataTypes::DeviceIdData deviceIdToRemove{ L"DELA026#5&10a58c63&0&UID16777489_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const FancyZonesDataTypes::WorkAreaId workAreaIdToRemove{
.monitorId = { .deviceId = { .id = L"DELA027", .instanceId = L"5&10a58c63&0&UID16777489" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = Mocks::WindowCreate(m_hInst); const auto window = Mocks::WindowCreate(m_hInst);
Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, deviceIdToInsert, zoneSetId, { 1 })); Assert::IsTrue(AppZoneHistory::instance().SetAppLastZones(window, workAreaIdToInsert, zoneSetId, { 1 }));
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, deviceIdToRemove, zoneSetId)); Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(window, workAreaIdToRemove, zoneSetId));
Assert::IsTrue(std::vector<ZoneIndex>{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, deviceIdToInsert, zoneSetId)); Assert::IsTrue(std::vector<ZoneIndex>{ 1 } == AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workAreaIdToInsert, zoneSetId));
} }
TEST_METHOD (AppLastZoneRemoveNullWindow) TEST_METHOD (AppLastZoneRemoveNullWindow)
{ {
const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}"; const std::wstring zoneSetId = L"{2FEC41DA-3A0B-4E31-9CE1-9473C65D99F2}";
const FancyZonesDataTypes::DeviceIdData deviceId{ L"DELA026#5&10a58c63&0&UID16777488_2194_1234_{39B25DD2-130D-4B5D-8851-4791D66B1539}" }; const FancyZonesDataTypes::WorkAreaId workAreaId{
.monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" } },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value()
};
const auto window = Mocks::WindowCreate(m_hInst); const auto window = Mocks::WindowCreate(m_hInst);
Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(nullptr, deviceId, zoneSetId)); Assert::IsFalse(AppZoneHistory::instance().RemoveAppLastZone(nullptr, workAreaId, zoneSetId));
} }
}; };
} }

View File

@@ -23,6 +23,7 @@ namespace FancyZonesUnitTests
{ {
std::filesystem::remove_all(AppliedLayouts::AppliedLayoutsFileName()); std::filesystem::remove_all(AppliedLayouts::AppliedLayoutsFileName());
std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_testFolder)); std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_testFolder));
AppliedLayouts::instance().LoadData(); // clean data
} }
TEST_METHOD (AppliedLayoutsParse) TEST_METHOD (AppliedLayoutsParse)
@@ -58,11 +59,12 @@ namespace FancyZonesUnitTests
AppliedLayouts::instance().LoadData(); AppliedLayouts::instance().LoadData();
Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size()); Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size());
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"DELA026#5&10a58c63&0&UID16777488", .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value()
}; };
Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value()); Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value());
Assert::IsTrue(AppliedLayouts::instance().IsLayoutApplied(id));
} }
TEST_METHOD(AppliedLayoutsParseDataWithResolution) TEST_METHOD(AppliedLayoutsParseDataWithResolution)
@@ -94,11 +96,12 @@ namespace FancyZonesUnitTests
AppliedLayouts::instance().LoadData(); AppliedLayouts::instance().LoadData();
Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size()); Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size());
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"DELA026#5&10a58c63&0&UID16777488", .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value()
}; };
Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value()); Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value());
Assert::IsTrue(AppliedLayouts::instance().IsLayoutApplied(id));
} }
TEST_METHOD (AppliedLayoutsParseDataWithResolution2) TEST_METHOD (AppliedLayoutsParseDataWithResolution2)
@@ -147,11 +150,12 @@ namespace FancyZonesUnitTests
AppliedLayouts::instance().LoadData(); AppliedLayouts::instance().LoadData();
Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size()); Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size());
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"DELA026#5&10a58c63&0&UID16777488", .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value()
}; };
Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value()); Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value());
Assert::IsTrue(AppliedLayouts::instance().IsLayoutApplied(id));
} }
TEST_METHOD (AppliedLayoutsParseDataWithResolution3) TEST_METHOD (AppliedLayoutsParseDataWithResolution3)
@@ -202,11 +206,12 @@ namespace FancyZonesUnitTests
AppliedLayouts::instance().LoadData(); AppliedLayouts::instance().LoadData();
Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size()); Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size());
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"DELA026#5&10a58c63&0&UID16777488", .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value()
}; };
Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value()); Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value());
Assert::IsTrue(AppliedLayouts::instance().IsLayoutApplied(id));
} }
TEST_METHOD (AppliedLayoutsParseEmpty) TEST_METHOD (AppliedLayoutsParseEmpty)
@@ -262,8 +267,8 @@ namespace FancyZonesUnitTests
AppliedLayouts::instance().LoadData(); AppliedLayouts::instance().LoadData();
Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size()); Assert::AreEqual((size_t)1, AppliedLayouts::instance().GetAppliedLayoutMap().size());
FancyZonesDataTypes::DeviceIdData id{ FancyZonesDataTypes::WorkAreaId id{
.deviceName = L"VSC9636#5&37ac4db&0&UID160005", .monitorId = { .deviceId = { .id = L"VSC9636", .instanceId = L"5&37ac4db&0&UID160005" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value()); Assert::IsTrue(AppliedLayouts::instance().GetDeviceLayout(id).has_value());
@@ -295,12 +300,12 @@ namespace FancyZonesUnitTests
TEST_METHOD (CloneDeviceInfo) TEST_METHOD (CloneDeviceInfo)
{ {
FancyZonesDataTypes::DeviceIdData deviceSrc{ FancyZonesDataTypes::WorkAreaId deviceSrc{
.deviceName = L"Device1", .monitorId = { .deviceId = { .id = L"Device1", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
FancyZonesDataTypes::DeviceIdData deviceDst{ FancyZonesDataTypes::WorkAreaId deviceDst{
.deviceName = L"Device2", .monitorId = { .deviceId = { .id = L"Device2", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
@@ -323,12 +328,12 @@ namespace FancyZonesUnitTests
TEST_METHOD (CloneDeviceInfoIntoUnknownDevice) TEST_METHOD (CloneDeviceInfoIntoUnknownDevice)
{ {
FancyZonesDataTypes::DeviceIdData deviceSrc{ FancyZonesDataTypes::WorkAreaId deviceSrc{
.deviceName = L"Device1", .monitorId = { .deviceId = { .id = L"Device1", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
FancyZonesDataTypes::DeviceIdData deviceDst{ FancyZonesDataTypes::WorkAreaId deviceDst{
.deviceName = L"Device2", .monitorId = { .deviceId = { .id = L"Device2", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
@@ -350,12 +355,12 @@ namespace FancyZonesUnitTests
TEST_METHOD (CloneDeviceInfoFromUnknownDevice) TEST_METHOD (CloneDeviceInfoFromUnknownDevice)
{ {
FancyZonesDataTypes::DeviceIdData deviceSrc{ FancyZonesDataTypes::WorkAreaId deviceSrc{
.deviceName = L"Device1", .monitorId = { .deviceId = { .id = L"Device1", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
FancyZonesDataTypes::DeviceIdData deviceDst{ FancyZonesDataTypes::WorkAreaId deviceDst{
.deviceName = L"Device2", .monitorId = { .deviceId = { .id = L"Device2", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
@@ -370,12 +375,12 @@ namespace FancyZonesUnitTests
TEST_METHOD (CloneDeviceInfoNullVirtualDesktopId) TEST_METHOD (CloneDeviceInfoNullVirtualDesktopId)
{ {
FancyZonesDataTypes::DeviceIdData deviceSrc{ FancyZonesDataTypes::WorkAreaId deviceSrc{
.deviceName = L"Device1", .monitorId = { .deviceId = { .id = L"Device1", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = GUID_NULL .virtualDesktopId = GUID_NULL
}; };
FancyZonesDataTypes::DeviceIdData deviceDst{ FancyZonesDataTypes::WorkAreaId deviceDst{
.deviceName = L"Device2", .monitorId = { .deviceId = { .id = L"Device2", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
@@ -399,8 +404,8 @@ namespace FancyZonesUnitTests
TEST_METHOD (ApplyLayout) TEST_METHOD (ApplyLayout)
{ {
// prepare // prepare
FancyZonesDataTypes::DeviceIdData deviceId { FancyZonesDataTypes::WorkAreaId deviceId {
.deviceName = L"DELA026#5&10a58c63&0&UID16777488", .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value()
}; };
@@ -430,8 +435,8 @@ namespace FancyZonesUnitTests
TEST_METHOD (ApplyLayoutReplace) TEST_METHOD (ApplyLayoutReplace)
{ {
// prepare // prepare
FancyZonesDataTypes::DeviceIdData deviceId{ FancyZonesDataTypes::WorkAreaId deviceId{
.deviceName = L"DELA026#5&10a58c63&0&UID16777488", .monitorId = { .deviceId = { .id = L"DELA026", .instanceId = L"5&10a58c63&0&UID16777488" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value()
}; };
@@ -482,8 +487,8 @@ namespace FancyZonesUnitTests
TEST_METHOD (ApplyDefaultLayout) TEST_METHOD (ApplyDefaultLayout)
{ {
FancyZonesDataTypes::DeviceIdData expected{ FancyZonesDataTypes::WorkAreaId expected{
.deviceName = L"Device", .monitorId = { .deviceId = { .id = L"Device", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value() .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{00000000-0000-0000-0000-000000000000}").value()
}; };
@@ -497,8 +502,8 @@ namespace FancyZonesUnitTests
TEST_METHOD (ApplyDefaultLayoutWithNullVirtualDesktopId) TEST_METHOD (ApplyDefaultLayoutWithNullVirtualDesktopId)
{ {
FancyZonesDataTypes::DeviceIdData expected{ FancyZonesDataTypes::WorkAreaId expected{
.deviceName = L"Device", .monitorId = { .deviceId = { .id = L"Device", .instanceId = L"" }, .serialNumber = L"" },
.virtualDesktopId = GUID_NULL .virtualDesktopId = GUID_NULL
}; };
@@ -509,5 +514,35 @@ namespace FancyZonesUnitTests
Assert::IsFalse(actualMap.find(expected) == actualMap.end()); Assert::IsFalse(actualMap.find(expected) == actualMap.end());
} }
TEST_METHOD (IsLayoutApplied)
{
// prepare
FancyZonesDataTypes::WorkAreaId id{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
AppliedLayouts::instance().ApplyLayout(id, Layout{});
// test
Assert::IsTrue(AppliedLayouts::instance().IsLayoutApplied(id));
}
TEST_METHOD (IsLayoutApplied2)
{
// prepare
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device-1", .instanceId = L"instance-id-1" }, .serialNumber = L"serial-number-1" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
AppliedLayouts::instance().ApplyLayout(id1, Layout{});
// test
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device-2", .instanceId = L"instance-id-2" }, .serialNumber = L"serial-number-2" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{F21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(AppliedLayouts::instance().IsLayoutApplied(id2));
}
}; };
} }

View File

@@ -741,15 +741,9 @@ namespace FancyZonesUnitTests
TEST_CLASS (DeviceInfoUnitTests) TEST_CLASS (DeviceInfoUnitTests)
{ {
private: private:
FancyZonesDataTypes::DeviceIdData m_defaultDeviceId{ .deviceName = L"AOC2460#4&fe3a015&0&UID65793", .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{33A2B101-06E0-437B-A61E-CDBECF502907}").value() };
DeviceInfoJSON m_defaultDeviceInfo = DeviceInfoJSON{ BackwardsCompatibility::DeviceIdData::ParseDeviceId(L"AOC2460#4&fe3a015&0&UID65793_1920_1080_{33A2B101-06E0-437B-A61E-CDBECF502907}").value(), DeviceInfoData{ ZoneSetData{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", ZoneSetLayoutType::Custom }, true, 16, 3 } }; DeviceInfoJSON m_defaultDeviceInfo = DeviceInfoJSON{ BackwardsCompatibility::DeviceIdData::ParseDeviceId(L"AOC2460#4&fe3a015&0&UID65793_1920_1080_{33A2B101-06E0-437B-A61E-CDBECF502907}").value(), DeviceInfoData{ ZoneSetData{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", ZoneSetLayoutType::Custom }, true, 16, 3 } };
json::JsonObject m_defaultJson = json::JsonObject::Parse(L"{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"active-zoneset\": {\"type\": \"custom\", \"uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\"}, \"editor-show-spacing\": true, \"editor-spacing\": 16, \"editor-zone-count\": 3}"); json::JsonObject m_defaultJson = json::JsonObject::Parse(L"{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"active-zoneset\": {\"type\": \"custom\", \"uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\"}, \"editor-show-spacing\": true, \"editor-spacing\": 16, \"editor-zone-count\": 3}");
TEST_METHOD_INITIALIZE(Init)
{
CLSIDFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", &m_defaultDeviceId.virtualDesktopId);
}
public: public:
TEST_METHOD (FromJson) TEST_METHOD (FromJson)
{ {
@@ -791,9 +785,7 @@ namespace FancyZonesUnitTests
const std::wstring m_defaultCustomDeviceStr = L"{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"active-zoneset\": {\"type\": \"custom\", \"uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\"}, \"editor-show-spacing\": true, \"editor-spacing\": 16, \"editor-zone-count\": 3}"; const std::wstring m_defaultCustomDeviceStr = L"{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"active-zoneset\": {\"type\": \"custom\", \"uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\"}, \"editor-show-spacing\": true, \"editor-spacing\": 16, \"editor-zone-count\": 3}";
const std::wstring m_defaultCustomLayoutStr = L"{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"applied-layout\": {\"type\": \"custom\", \"uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"show-spacing\": true, \"spacing\": 16, \"zone-count\": 3, \"sensitivity-radius\": 30}}"; const std::wstring m_defaultCustomLayoutStr = L"{\"device-id\": \"AOC2460#4&fe3a015&0&UID65793_1920_1200_{39B25DD2-130D-4B5D-8851-4791D66B1539}\", \"applied-layout\": {\"type\": \"custom\", \"uuid\": \"{33A2B101-06E0-437B-A61E-CDBECF502906}\", \"show-spacing\": true, \"spacing\": 16, \"zone-count\": 3, \"sensitivity-radius\": 30}}";
const json::JsonValue m_defaultCustomDeviceValue = json::JsonValue::Parse(m_defaultCustomDeviceStr); const json::JsonValue m_defaultCustomDeviceValue = json::JsonValue::Parse(m_defaultCustomDeviceStr);
const FancyZonesDataTypes::DeviceIdData m_defaultDeviceId = FancyZonesDataTypes::DeviceIdData{ .deviceName = L"AOC2460#4&fe3a015&0&UID65793", .virtualDesktopId = FancyZonesUtils::GuidFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}").value() };
TEST_METHOD_INITIALIZE(Init) TEST_METHOD_INITIALIZE(Init)
{ {
std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_moduleName)); std::filesystem::remove_all(PTSettingsHelper::get_module_save_folder_location(m_moduleName));

View File

@@ -37,7 +37,7 @@
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>gdiplus.lib;dwmapi.lib;shlwapi.lib;uxtheme.lib;shcore.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>gdiplus.lib;dwmapi.lib;shlwapi.lib;uxtheme.lib;shcore.lib;wbemuuid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
@@ -55,6 +55,7 @@
<ClCompile Include="Util.Spec.cpp" /> <ClCompile Include="Util.Spec.cpp" />
<ClCompile Include="Util.cpp" /> <ClCompile Include="Util.cpp" />
<ClCompile Include="WorkArea.Spec.cpp" /> <ClCompile Include="WorkArea.Spec.cpp" />
<ClCompile Include="WorkAreaIdTests.Spec.cpp" />
<ClCompile Include="Zone.Spec.cpp" /> <ClCompile Include="Zone.Spec.cpp" />
<ClCompile Include="ZoneSet.Spec.cpp" /> <ClCompile Include="ZoneSet.Spec.cpp" />
</ItemGroup> </ItemGroup>

View File

@@ -57,6 +57,9 @@
<ClCompile Include="AppliedLayoutsTests.Spec.cpp"> <ClCompile Include="AppliedLayoutsTests.Spec.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="WorkAreaIdTests.Spec.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="pch.h"> <ClInclude Include="pch.h">

View File

@@ -41,28 +41,6 @@ namespace FancyZonesUnitTests
TEST_CLASS(UtilUnitTests) TEST_CLASS(UtilUnitTests)
{ {
TEST_METHOD (TestTrimDeviceId)
{
// We're interested in the unique part between the first and last #'s
// Example input: \\?\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
// Example output: DELA026#5&10a58c63&0&UID16777488
const std::wstring input = L"\\\\?\\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}";
const std::wstring actual = TrimDeviceId(input);
const std::wstring expected = L"DELA026#5&10a58c63&0&UID16777488";
Assert::AreEqual(expected, actual);
}
TEST_METHOD(TestTrimInvalidDeviceId)
{
// We're interested in the unique part between the first and last #'s
// Example input: \\?\DISPLAY#DELA026#5&10a58c63&0&UID16777488#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
// Example output: DELA026#5&10a58c63&0&UID16777488
const std::wstring input = L"AnInvalidDeviceId";
const std::wstring actual = TrimDeviceId(input);
const std::wstring expected = L"FallbackDevice";
Assert::AreEqual(expected, actual);
}
TEST_METHOD(TestParseDeviceId01) TEST_METHOD(TestParseDeviceId01)
{ {
const std::wstring input = L"AOC0001#5&37ac4db&0&UID160002_1536_960_{E0A2904E-889C-4532-95B1-28FE15C16F66}"; const std::wstring input = L"AOC0001#5&37ac4db&0&UID160002_1536_960_{E0A2904E-889C-4532-95B1-28FE15C16F66}";

View File

@@ -23,12 +23,14 @@ namespace FancyZonesUnitTests
TEST_CLASS (WorkAreaCreationUnitTests) TEST_CLASS (WorkAreaCreationUnitTests)
{ {
FancyZonesDataTypes::DeviceIdData m_uniqueId; FancyZonesDataTypes::WorkAreaId m_uniqueId;
FancyZonesDataTypes::DeviceIdData m_emptyUniqueId; FancyZonesDataTypes::WorkAreaId m_emptyUniqueId;
TEST_METHOD_INITIALIZE(Init) TEST_METHOD_INITIALIZE(Init)
{ {
m_uniqueId.deviceName = L"DELA026#5&10a58c63&0&UID16777488"; m_uniqueId.monitorId.deviceId.id = L"DELA026";
m_uniqueId.monitorId.deviceId.instanceId = L"5&10a58c63&0&UID16777488";
m_uniqueId.monitorId.serialNumber = L"serial-number";
auto res = CLSIDFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", &m_uniqueId.virtualDesktopId); auto res = CLSIDFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", &m_uniqueId.virtualDesktopId);
Assert::IsTrue(SUCCEEDED(res)); Assert::IsTrue(SUCCEEDED(res));
@@ -70,8 +72,10 @@ namespace FancyZonesUnitTests
{ {
using namespace FancyZonesDataTypes; using namespace FancyZonesDataTypes;
FancyZonesDataTypes::DeviceIdData parentUniqueId; FancyZonesDataTypes::WorkAreaId parentUniqueId;
parentUniqueId.deviceName = L"DELA026#5&10a58c63&0&UID16777488"; parentUniqueId.monitorId.deviceId.id = L"DELA026";
parentUniqueId.monitorId.deviceId.instanceId = L"5&10a58c63&0&UID16777488";
parentUniqueId.monitorId.serialNumber = L"serial-number";
parentUniqueId.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value(); parentUniqueId.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{61FA9FC0-26A6-4B37-A834-491C148DFC57}").value();
Layout layout{ Layout layout{
@@ -104,15 +108,17 @@ namespace FancyZonesUnitTests
TEST_CLASS (WorkAreaUnitTests) TEST_CLASS (WorkAreaUnitTests)
{ {
FancyZonesDataTypes::DeviceIdData m_uniqueId; FancyZonesDataTypes::WorkAreaId m_uniqueId;
FancyZonesDataTypes::DeviceIdData m_parentUniqueId; // default empty FancyZonesDataTypes::WorkAreaId m_parentUniqueId; // default empty
HINSTANCE m_hInst{}; HINSTANCE m_hInst{};
HMONITOR m_monitor{}; HMONITOR m_monitor{};
TEST_METHOD_INITIALIZE(Init) TEST_METHOD_INITIALIZE(Init)
{ {
m_uniqueId.deviceName = L"DELA026#5&10a58c63&0&UID16777488"; m_uniqueId.monitorId.deviceId.id = L"DELA026";
m_uniqueId.monitorId.deviceId.instanceId = L"5&10a58c63&0&UID16777488";
m_uniqueId.monitorId.serialNumber = L"serial-number";
CLSIDFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", &m_uniqueId.virtualDesktopId); CLSIDFromString(L"{39B25DD2-130D-4B5D-8851-4791D66B1539}", &m_uniqueId.virtualDesktopId);
AppZoneHistory::instance().LoadData(); AppZoneHistory::instance().LoadData();

View File

@@ -0,0 +1,212 @@
#include "pch.h"
#include <FancyZonesLib/FancyZonesDataTypes.h>
#include <FancyZonesLib/util.h>
#include <FancyZonesTests/UnitTests/Util.h>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace FancyZonesUnitTests
{
TEST_CLASS (WorkAreaIdComparison)
{
TEST_METHOD (MonitorHandleSame)
{
auto monitor = Mocks::Monitor();
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .monitor = monitor, .deviceId = { .id = L"device-1", .instanceId = L"instance-id-1" }, .serialNumber = L"serial-number-1" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .monitor = monitor, .deviceId = { .id = L"device-2", .instanceId = L"instance-id-2" }, .serialNumber = L"serial-number-2" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsTrue(id1 == id2);
}
TEST_METHOD (MonitorHandleDifferent)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .monitor = Mocks::Monitor(), .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .monitor = Mocks::Monitor(), .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
TEST_METHOD (VirtualDesktopNull)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = GUID_NULL
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsTrue(id1 == id2);
}
TEST_METHOD (VirtualDesktopDifferent)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{F21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
TEST_METHOD (NoSerialNumber)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
TEST_METHOD (NoSerialNumber2)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
TEST_METHOD (DifferentSerialNumber)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id" }, .serialNumber = L"another-serial-number" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
TEST_METHOD (DefaultMonitorIdDifferentInstanceId)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"Default_Monitor", .instanceId = L"instance-id" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"Default_Monitor", .instanceId = L"another-instance-id" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
TEST_METHOD (DefaultMonitorIdSameInstanceId)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"Default_Monitor", .instanceId = L"instance-id" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"Default_Monitor", .instanceId = L"instance-id" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsTrue(id1 == id2);
}
TEST_METHOD (DifferentId)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device-1", .instanceId = L"instance-id" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device-2", .instanceId = L"instance-id" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
TEST_METHOD (SameIdDifferentInstance)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id-1" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device", .instanceId = L"instance-id-2" }, .serialNumber = L"" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsTrue(id1 == id2);
}
TEST_METHOD (SameIdDifferentSerialNumbers)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device-1", .instanceId = L"instance-id-1" }, .serialNumber = L"serial-number-1" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device-1", .instanceId = L"instance-id-2" }, .serialNumber = L"serial-number-2" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
TEST_METHOD (DifferentIdSameSerialNumbers)
{
FancyZonesDataTypes::WorkAreaId id1{
.monitorId = { .deviceId = { .id = L"device-1", .instanceId = L"instance-id-1" }, .serialNumber = L"serial-number-1" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
FancyZonesDataTypes::WorkAreaId id2{
.monitorId = { .deviceId = { .id = L"device-2", .instanceId = L"instance-id-2" }, .serialNumber = L"serial-number-1" },
.virtualDesktopId = FancyZonesUtils::GuidFromString(L"{E21F6F29-76FD-4FC1-8970-17AB8AD64847}").value()
};
Assert::IsFalse(id1 == id2);
}
};
}

View File

@@ -13,6 +13,10 @@ namespace FancyZonesEditor.Utils
{ {
public string MonitorName { get; set; } public string MonitorName { get; set; }
public string MonitorInstanceId { get; set; }
public string MonitorSerialNumber { get; set; }
public Size MonitorSize { get; set; } public Size MonitorSize { get; set; }
public string VirtualDesktopId { get; set; } public string VirtualDesktopId { get; set; }
@@ -23,9 +27,11 @@ namespace FancyZonesEditor.Utils
public int Dpi { get; set; } public int Dpi { get; set; }
public Device(string monitorName, string virtualDesktopId, int dpi, Rect workArea, Size monitorSize) public Device(string monitorName, string monitorInstanceId, string monitorSerialNumber, string virtualDesktopId, int dpi, Rect workArea, Size monitorSize)
{ {
MonitorName = monitorName; MonitorName = monitorName;
MonitorInstanceId = monitorInstanceId;
MonitorSerialNumber = monitorSerialNumber;
VirtualDesktopId = virtualDesktopId; VirtualDesktopId = virtualDesktopId;
Dpi = dpi; Dpi = dpi;
WorkAreaRect = workArea; WorkAreaRect = workArea;
@@ -48,6 +54,8 @@ namespace FancyZonesEditor.Utils
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendFormat(CultureInfo.InvariantCulture, "MonitorName: {0}{1}", MonitorName, Environment.NewLine); sb.AppendFormat(CultureInfo.InvariantCulture, "MonitorName: {0}{1}", MonitorName, Environment.NewLine);
sb.AppendFormat(CultureInfo.InvariantCulture, "Monitor InstanceId {0}{1}", MonitorInstanceId, Environment.NewLine);
sb.AppendFormat(CultureInfo.InvariantCulture, "Monitor Serial Number {0}{1}", MonitorSerialNumber, Environment.NewLine);
sb.AppendFormat(CultureInfo.InvariantCulture, "Virtual desktop: {0}{1}", VirtualDesktopId, Environment.NewLine); sb.AppendFormat(CultureInfo.InvariantCulture, "Virtual desktop: {0}{1}", VirtualDesktopId, Environment.NewLine);
sb.AppendFormat(CultureInfo.InvariantCulture, "DPI: {0}{1}", Dpi, Environment.NewLine); sb.AppendFormat(CultureInfo.InvariantCulture, "DPI: {0}{1}", Dpi, Environment.NewLine);

View File

@@ -41,10 +41,10 @@ namespace FancyZonesEditor.Models
Window.Height = workArea.Height; Window.Height = workArea.Height;
} }
public Monitor(string monitorName, string virtualDesktop, int dpi, Rect workArea, Size monitorSize) public Monitor(string monitorName, string monitorInstanceId, string monitorSerialNumber, string virtualDesktop, int dpi, Rect workArea, Size monitorSize)
: this(workArea, monitorSize) : this(workArea, monitorSize)
{ {
Device = new Device(monitorName, virtualDesktop, dpi, workArea, monitorSize); Device = new Device(monitorName, monitorInstanceId, monitorSerialNumber, virtualDesktop, dpi, workArea, monitorSize);
} }
public void Scale(double scaleFactor) public void Scale(double scaleFactor)

View File

@@ -77,6 +77,10 @@ namespace FancyZonesEditor.Utils
{ {
public string Monitor { get; set; } public string Monitor { get; set; }
public string MonitorInstanceId { get; set; }
public string MonitorSerialNumber { get; set; }
public string VirtualDesktop { get; set; } public string VirtualDesktop { get; set; }
public int Dpi { get; set; } public int Dpi { get; set; }
@@ -128,6 +132,10 @@ namespace FancyZonesEditor.Utils
{ {
public string Monitor { get; set; } public string Monitor { get; set; }
public string MonitorInstance { get; set; }
public string SerialNumber { get; set; }
public string VirtualDesktop { get; set; } public string VirtualDesktop { get; set; }
} }
@@ -309,6 +317,7 @@ namespace FancyZonesEditor.Utils
if (!App.Overlay.SpanZonesAcrossMonitors) if (!App.Overlay.SpanZonesAcrossMonitors)
{ {
string targetMonitorId = string.Empty; string targetMonitorId = string.Empty;
string targetMonitorSerialNumber = string.Empty;
string targetVirtualDesktop = string.Empty; string targetVirtualDesktop = string.Empty;
foreach (NativeMonitorData nativeData in editorParams.Monitors) foreach (NativeMonitorData nativeData in editorParams.Monitors)
@@ -317,6 +326,7 @@ namespace FancyZonesEditor.Utils
if (nativeData.IsSelected) if (nativeData.IsSelected)
{ {
targetMonitorId = nativeData.Monitor; targetMonitorId = nativeData.Monitor;
targetMonitorSerialNumber = nativeData.MonitorSerialNumber;
targetVirtualDesktop = nativeData.VirtualDesktop; targetVirtualDesktop = nativeData.VirtualDesktop;
} }
@@ -324,6 +334,8 @@ namespace FancyZonesEditor.Utils
var monitor = new Monitor(workArea, monitorSize); var monitor = new Monitor(workArea, monitorSize);
monitor.Device.MonitorName = nativeData.Monitor; monitor.Device.MonitorName = nativeData.Monitor;
monitor.Device.MonitorInstanceId = nativeData.MonitorInstanceId;
monitor.Device.MonitorSerialNumber = nativeData.MonitorSerialNumber;
monitor.Device.VirtualDesktopId = nativeData.VirtualDesktop; monitor.Device.VirtualDesktopId = nativeData.VirtualDesktop;
monitor.Device.Dpi = nativeData.Dpi; monitor.Device.Dpi = nativeData.Dpi;
@@ -335,7 +347,9 @@ namespace FancyZonesEditor.Utils
for (int i = 0; i < monitors.Count; i++) for (int i = 0; i < monitors.Count; i++)
{ {
var monitor = monitors[i]; var monitor = monitors[i];
if (monitor.Device.MonitorName == targetMonitorId && monitor.Device.VirtualDesktopId == targetVirtualDesktop) if (monitor.Device.MonitorName == targetMonitorId &&
monitor.Device.MonitorSerialNumber == targetMonitorSerialNumber &&
monitor.Device.VirtualDesktopId == targetVirtualDesktop)
{ {
App.Overlay.CurrentDesktop = i; App.Overlay.CurrentDesktop = i;
break; break;
@@ -554,6 +568,8 @@ namespace FancyZonesEditor.Utils
Device = new AppliedLayoutWrapper.DeviceIdWrapper Device = new AppliedLayoutWrapper.DeviceIdWrapper
{ {
Monitor = monitor.Device.MonitorName, Monitor = monitor.Device.MonitorName,
MonitorInstance = monitor.Device.MonitorInstanceId,
SerialNumber = monitor.Device.MonitorSerialNumber,
VirtualDesktop = monitor.Device.VirtualDesktopId, VirtualDesktop = monitor.Device.VirtualDesktopId,
}, },
@@ -818,7 +834,10 @@ namespace FancyZonesEditor.Utils
bool unused = true; bool unused = true;
foreach (Monitor monitor in monitors) foreach (Monitor monitor in monitors)
{ {
if (monitor.Device.MonitorName == layout.Device.Monitor && (monitor.Device.VirtualDesktopId == layout.Device.VirtualDesktop || layout.Device.VirtualDesktop == DefaultVirtualDesktopGuid)) if (monitor.Device.MonitorName == layout.Device.Monitor &&
monitor.Device.MonitorSerialNumber == layout.Device.SerialNumber &&
(monitor.Device.VirtualDesktopId == layout.Device.VirtualDesktop ||
layout.Device.VirtualDesktop == DefaultVirtualDesktopGuid))
{ {
var settings = new LayoutSettings var settings = new LayoutSettings
{ {