Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce handling of new/old work areas #1296

Merged
merged 10 commits into from
Feb 18, 2020
97 changes: 72 additions & 25 deletions src/modules/fancyzones/lib/FancyZones.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <functional>
#include <common/common.h>
#include <lib\util.h>
#include <unordered_set>

enum class DisplayChangeType
{
Expand Down Expand Up @@ -136,7 +137,12 @@ struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZone
void MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT const& ptScreen, require_write_lock) noexcept;
void MoveSizeEndInternal(HWND window, POINT const& ptScreen, require_write_lock) noexcept;
void MoveSizeUpdateInternal(HMONITOR monitor, POINT const& ptScreen, require_write_lock) noexcept;

void HandleVirtualDesktopUpdates(HANDLE fancyZonesDestroyedEvent) noexcept;
void RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& currentVirtualDesktopIds) noexcept;
void RegisterNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept;
bool IsNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept;

void OnEditorExitEvent() noexcept;

const HINSTANCE m_hinstance{};
Expand All @@ -152,7 +158,7 @@ struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZone
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors.
winrt::com_ptr<IFancyZonesSettings> m_settings{};
GUID m_currentVirtualDesktopId{}; // UUID of the current virtual desktop. Is GUID_NULL until first VD switch per session.
std::unordered_map<GUID, bool> m_virtualDesktopIds;
std::unordered_map<GUID, std::vector<HMONITOR>> m_processedWorkAreas; // Work area is defined by monitor and virtual desktop id.
wil::unique_handle m_terminateEditorEvent; // Handle of FancyZonesEditor.exe we launch and wait on
wil::unique_handle m_terminateVirtualDesktopTrackerEvent;

Expand Down Expand Up @@ -608,22 +614,21 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
if (SUCCEEDED_LOG(StringFromCLSID(m_currentVirtualDesktopId, &virtualDesktopId)))
{
std::wstring uniqueId = ZoneWindowUtils::GenerateUniqueId(monitor, deviceId, virtualDesktopId.get());
bool newVirtualDesktop = true;
JSONHelpers::FancyZonesDataInstance().SetActiveDeviceId(uniqueId);

auto it = m_virtualDesktopIds.find(m_currentVirtualDesktopId);
if (it != end(m_virtualDesktopIds))
{
newVirtualDesktop = it->second;
JSONHelpers::FancyZonesDataInstance().SetActiveDeviceId(uniqueId);
}
const bool newWorkArea = IsNewWorkArea(m_currentVirtualDesktopId, monitor);
const bool flash = m_settings->GetSettings().zoneSetChange_flashZones && newWorkArea;

const bool flash = m_settings->GetSettings().zoneSetChange_flashZones && newVirtualDesktop;
auto zoneWindow = MakeZoneWindow(this, m_hinstance, monitor, uniqueId, flash);
if (zoneWindow)
{
m_zoneWindowMap[monitor] = std::move(zoneWindow);
}
m_virtualDesktopIds[m_currentVirtualDesktopId] = false;
if (newWorkArea)
{
RegisterNewWorkArea(m_currentVirtualDesktopId, monitor);
JSONHelpers::FancyZonesDataInstance().SaveFancyZonesData();
}
}
}

Expand Down Expand Up @@ -961,31 +966,73 @@ void FancyZones::HandleVirtualDesktopUpdates(HANDLE fancyZonesDestroyedEvent) no
{
return;
}
const int guidSize = sizeof(GUID);
std::unordered_map<GUID, bool> temp;
const size_t guidSize = sizeof(GUID);
std::unordered_set<GUID> temp;
temp.reserve(bufferCapacity / guidSize);
for (size_t i = 0; i < bufferCapacity; i += guidSize)
{
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
temp[*guid] = true;
temp.insert(*guid);
}
std::unique_lock writeLock(m_lock);
for (auto it = begin(m_virtualDesktopIds); it != end(m_virtualDesktopIds);)
RegisterVirtualDesktopUpdates(temp);
}
}

void FancyZones::RegisterVirtualDesktopUpdates(std::unordered_set<GUID>& currentVirtualDesktopIds) noexcept
{
std::unique_lock writeLock(m_lock);
bool modified{ false };
for (auto it = begin(m_processedWorkAreas); it != end(m_processedWorkAreas);)
{
auto iter = currentVirtualDesktopIds.find(it->first);
if (iter == currentVirtualDesktopIds.end())
{
auto iter = temp.find(it->first);
if (iter == temp.end())
// if we couldn't find the GUID in currentVirtualDesktopIds, we must remove it from both m_processedWorkAreas and deviceInfoMap
wil::unique_cotaskmem_string virtualDesktopId;
if (SUCCEEDED_LOG(StringFromCLSID(it->first, &virtualDesktopId)))
{
it = m_virtualDesktopIds.erase(it); // virtual desktop closed, remove it from map
}
else
{
temp.erase(it->first); // virtual desktop already in map, skip it
++it;
modified |= JSONHelpers::FancyZonesDataInstance().RemoveDevicesByVirtualDesktopId(virtualDesktopId.get());
}
it = m_processedWorkAreas.erase(it);
}
else
{
currentVirtualDesktopIds.erase(it->first); // virtual desktop already in map, skip it
++it;
}
// register new virtual desktops, if any
m_virtualDesktopIds.insert(begin(temp), end(temp));
}
if (modified)
{
JSONHelpers::FancyZonesDataInstance().SaveFancyZonesData();
}
// register new virtual desktops, if any
for (const auto& id : currentVirtualDesktopIds)
{
m_processedWorkAreas[id] = std::vector<HMONITOR>();
}
}

void FancyZones::RegisterNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept
{
if (!m_processedWorkAreas.contains(virtualDesktopId))
{
m_processedWorkAreas[virtualDesktopId] = { monitor };
}
else
{
m_processedWorkAreas[virtualDesktopId].push_back(monitor);
}
}

bool FancyZones::IsNewWorkArea(GUID virtualDesktopId, HMONITOR monitor) noexcept
{
auto it = m_processedWorkAreas.find(virtualDesktopId);
if (it != m_processedWorkAreas.end())
{
// virtual desktop exists, check if it's processed on given monitor
return std::find(it->second.begin(), it->second.end(), monitor) == it->second.end();
yuyoyuppe marked this conversation as resolved.
Show resolved Hide resolved
}
return true;
}

void FancyZones::OnEditorExitEvent() noexcept
Expand Down
59 changes: 31 additions & 28 deletions src/modules/fancyzones/lib/JsonHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ namespace
constexpr int c_blankCustomModelId = 0xFFFA;

const wchar_t* FANCY_ZONES_DATA_FILE = L"zones-settings.json";
const wchar_t* DEFAULT_GUID = L"{00000000-0000-0000-0000-000000000000}";

std::wstring ExtractVirtualDesktopId(const std::wstring& deviceId)
{
// Format: <device-id>_<resolution>_<virtual-desktop-id>
vldmr11080 marked this conversation as resolved.
Show resolved Hide resolved
return deviceId.substr(deviceId.rfind('_') + 1);
}
}

namespace JSONHelpers
Expand Down Expand Up @@ -160,10 +167,30 @@ namespace JSONHelpers
if (!deviceInfoMap.contains(deviceId))
{
// Creates default entry in map when ZoneWindow is created
deviceInfoMap[deviceId] = DeviceInfoData{ ZoneSetData{ L"null", ZoneSetLayoutType::Blank } };
deviceInfoMap[deviceId] = DeviceInfoData{ ZoneSetData{ L"null", ZoneSetLayoutType::Blank } };
}
}

MigrateDeviceInfoFromRegistry(deviceId);
bool FancyZonesData::RemoveDevicesByVirtualDesktopId(const std::wstring& virtualDesktopId)
{
if (virtualDesktopId == DEFAULT_GUID)
{
return false;
}
bool modified{ false };
for (auto it = deviceInfoMap.begin(); it != deviceInfoMap.end();)
{
if (ExtractVirtualDesktopId(it->first) == virtualDesktopId)
{
it = deviceInfoMap.erase(it);
modified = true;
}
else
{
++it;
}
}
return modified;
}

void FancyZonesData::CloneDeviceInfo(const std::wstring& source, const std::wstring& destination)
Expand Down Expand Up @@ -386,7 +413,8 @@ namespace JSONHelpers

for (const auto& [deviceID, deviceData] : deviceInfoMap)
{
if (deviceData.activeZoneSet.type != ZoneSetLayoutType::Blank) {
if (deviceData.activeZoneSet.type != ZoneSetLayoutType::Blank)
{
DeviceInfosJSON.Append(DeviceInfoJSON::DeviceInfoJSON::ToJson(DeviceInfoJSON{ deviceID, deviceData }));
}
}
Expand Down Expand Up @@ -519,31 +547,6 @@ namespace JSONHelpers
}
}

void FancyZonesData::MigrateDeviceInfoFromRegistry(const std::wstring& deviceId)
{
wchar_t key[256];
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", RegistryHelpers::REG_SETTINGS, deviceId.c_str());

wchar_t activeZoneSetId[256];
activeZoneSetId[0] = '\0';
DWORD bufferSize = sizeof(activeZoneSetId);
DWORD showSpacing = 1;
DWORD spacing = 16;
DWORD zoneCount = 3;
DWORD size = sizeof(DWORD);

SHRegGetUSValueW(key, L"ActiveZoneSetId", nullptr, &activeZoneSetId, &bufferSize, FALSE, nullptr, 0);
SHRegGetUSValueW(key, L"ShowSpacing", nullptr, &showSpacing, &size, FALSE, nullptr, 0);
SHRegGetUSValueW(key, L"Spacing", nullptr, &spacing, &size, FALSE, nullptr, 0);
SHRegGetUSValueW(key, L"ZoneCount", nullptr, &zoneCount, &size, FALSE, nullptr, 0);

if (appliedZoneSetsMap.contains(std::wstring{ activeZoneSetId }))
{
deviceInfoMap[deviceId] = DeviceInfoData{ appliedZoneSetsMap.at(std::wstring{ activeZoneSetId }), static_cast<bool>(showSpacing), static_cast<int>(spacing), static_cast<int>(zoneCount) };
SaveFancyZonesData();
}
}

void FancyZonesData::MigrateCustomZoneSetsFromRegistry()
{
wchar_t key[256];
Expand Down
3 changes: 1 addition & 2 deletions src/modules/fancyzones/lib/JsonHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ namespace JSONHelpers
}

void AddDevice(const std::wstring& deviceId);
bool RemoveDevicesByVirtualDesktopId(const std::wstring& virtualDesktopId);
void CloneDeviceInfo(const std::wstring& source, const std::wstring& destination);

int GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const;
Expand All @@ -221,8 +222,6 @@ namespace JSONHelpers
void LoadFancyZonesData();
void SaveFancyZonesData() const;

void MigrateDeviceInfoFromRegistry(const std::wstring& deviceId);

private:
void TmpMigrateAppliedZoneSetsFromRegistry();
void MigrateCustomZoneSetsFromRegistry();
Expand Down