Skip to content

Commit

Permalink
App zone history (microsoft#18)
Browse files Browse the repository at this point in the history
* added window and zone set ids to app zone history
  • Loading branch information
SeraphimaZykova authored Feb 5, 2020
1 parent 413ade3 commit fd094a1
Show file tree
Hide file tree
Showing 7 changed files with 406 additions and 119 deletions.
92 changes: 68 additions & 24 deletions src/modules/fancyzones/lib/FancyZones.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,11 @@ struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZone
{
//NOTE: as public method it's unsafe without lock, but it's called from AddZoneWindow through making ZoneWindow that causes deadlock
//TODO: needs refactoring
if (auto it = m_zoneWindowMap.find(monitor); it != m_zoneWindowMap.end())
auto it = m_zoneWindowMap.find(monitor);
if (it != m_zoneWindowMap.end())
{
return it->second->ActiveZoneSet();
const auto& zoneWindowPtr = it->second;
return zoneWindowPtr->ActiveZoneSet();
}
return nullptr;
}
Expand Down Expand Up @@ -271,15 +273,28 @@ IFACEMETHODIMP_(void) FancyZones::WindowCreated(HWND window) noexcept
{
if (m_settings->GetSettings().appLastZone_moveWindows)
{
auto processPath = get_process_path(window);
if (!processPath.empty())
auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
{
const auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();
int zoneIndex = fancyZonesData.GetAppLastZone(window, processPath.data());

if (zoneIndex != -1)
auto zoneWindow = m_zoneWindowMap.find(monitor);
if (zoneWindow != m_zoneWindowMap.end())
{
MoveWindowIntoZoneByIndex(window, zoneIndex);
const auto& zoneWindowPtr = zoneWindow->second;
const auto activeZoneSet = zoneWindowPtr->ActiveZoneSet();
if (activeZoneSet)
{
const auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();

wil::unique_cotaskmem_string guidString;
if (SUCCEEDED_LOG(StringFromCLSID(activeZoneSet->Id(), &guidString)))
{
int zoneIndex = fancyZonesData.GetAppLastZoneIndex(window, zoneWindowPtr->UniqueId(), guidString.get());
if (zoneIndex != -1)
{
MoveWindowIntoZoneByIndex(window, zoneIndex);
}
}
}
}
}
}
Expand Down Expand Up @@ -588,14 +603,17 @@ void FancyZones::AddZoneWindow(HMONITOR monitor, PCWSTR deviceId) noexcept
{
std::wstring uniqueId = ZoneWindowUtils::GenerateUniqueId(monitor, deviceId, virtualDesktopId.get());
bool newVirtualDesktop = true;
if (auto it = m_virtualDesktopIds.find(m_currentVirtualDesktopId); it != end(m_virtualDesktopIds))

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

if (auto zoneWindow = MakeZoneWindow(this, m_hinstance, monitor, uniqueId, flash))
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);
}
Expand All @@ -608,12 +626,14 @@ void FancyZones::MoveWindowIntoZoneByIndex(HWND window, int index) noexcept
std::shared_lock readLock(m_lock);
if (window != m_windowMoveSize)
{
if (const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL))
const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
{
auto iter = m_zoneWindowMap.find(monitor);
if (iter != m_zoneWindowMap.end())
{
iter->second->MoveWindowIntoZoneByIndex(window, index);
const auto& zoneWindowPtr = iter->second;
zoneWindowPtr->MoveWindowIntoZoneByIndex(window, index);
}
}
}
Expand Down Expand Up @@ -723,39 +743,49 @@ void FancyZones::UpdateDragState(require_write_lock) noexcept

void FancyZones::CycleActiveZoneSet(DWORD vkCode) noexcept
{
if (const HWND window = get_filtered_active_window())
const HWND window = get_filtered_active_window();
if (window)
{
if (GetWindow(window, GW_OWNER) != nullptr)
{
return;
}
if (const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL))

const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
{
std::shared_lock readLock(m_lock);

auto iter = m_zoneWindowMap.find(monitor);
if (iter != m_zoneWindowMap.end())
{
iter->second->CycleActiveZoneSet(vkCode);
const auto& zoneWindowPtr = iter->second;
zoneWindowPtr->CycleActiveZoneSet(vkCode);
}
}
}
}

void FancyZones::OnSnapHotkey(DWORD vkCode) noexcept
{
if (const HWND window = get_filtered_active_window())
const HWND window = get_filtered_active_window();
if (window)
{
if (GetWindow(window, GW_OWNER) != nullptr)
{
return;
}
if (const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL))

const HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
{
std::shared_lock readLock(m_lock);

auto iter = m_zoneWindowMap.find(monitor);
if (iter != m_zoneWindowMap.end())
{
iter->second->MoveWindowIntoZoneByDirection(window, vkCode);
const auto& zoneWindowPtr = iter->second;
zoneWindowPtr->MoveWindowIntoZoneByDirection(window, vkCode);
}
}
}
Expand Down Expand Up @@ -819,10 +849,23 @@ void FancyZones::MoveSizeEndInternal(HWND window, POINT const& ptScreen, require
{
::RemoveProp(window, ZONE_STAMP);

auto processPath = get_process_path(window);
if (!processPath.empty())
auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
if (monitor)
{
JSONHelpers::FancyZonesDataInstance().SetAppLastZone(window, processPath.data(), -1);
auto zoneWindow = m_zoneWindowMap.find(monitor);
if (zoneWindow != m_zoneWindowMap.end())
{
const auto zoneWindowPtr = zoneWindow->second;
const auto activeZoneSet = zoneWindowPtr->ActiveZoneSet();
if (activeZoneSet)
{
wil::unique_cotaskmem_string guidString;
if (SUCCEEDED_LOG(StringFromCLSID(activeZoneSet->Id(), &guidString)))
{
JSONHelpers::FancyZonesDataInstance().RemoveAppLastZone(window, zoneWindowPtr->UniqueId(), guidString.get());
}
}
}
}
}
}
Expand Down Expand Up @@ -909,7 +952,8 @@ void FancyZones::HandleVirtualDesktopUpdates(HANDLE fancyZonesDestroyedEvent) no
std::unique_lock writeLock(m_lock);
for (auto it = begin(m_virtualDesktopIds); it != end(m_virtualDesktopIds);)
{
if (auto iter = temp.find(it->first); iter == temp.end())
auto iter = temp.find(it->first);
if (iter == temp.end())
{
it = m_virtualDesktopIds.erase(it); // virtual desktop closed, remove it from map
}
Expand Down
65 changes: 43 additions & 22 deletions src/modules/fancyzones/lib/JsonHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "RegistryHelpers.h"
#include "ZoneSet.h"

#include <common/common.h>

#include <shlwapi.h>
#include <filesystem>
#include <fstream>
Expand Down Expand Up @@ -156,40 +158,57 @@ namespace JSONHelpers
}
}

int FancyZonesData::GetAppLastZone(HWND window, PCWSTR appPath) const
int FancyZonesData::GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const
{
int iZoneIndex = -1;

if (auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL))
auto processPath = get_process_path(window);
if (!processPath.empty())
{
std::wstring path{ appPath };
if (appZoneHistoryMap.contains(path))
auto history = appZoneHistoryMap.find(processPath);
if (history != appZoneHistoryMap.end())
{
iZoneIndex = appZoneHistoryMap.at(path).zoneIndex;
const auto& data = history->second;
if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId)
{
return history->second.zoneIndex;
}
}
}
return iZoneIndex;

return -1;
}

// Pass -1 for the zoneIndex to delete the entry from the map
bool FancyZonesData::SetAppLastZone(HWND window, PCWSTR appPath, DWORD zoneIndex)
bool FancyZonesData::RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId)
{
if (auto monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONULL))
auto processPath = get_process_path(window);
if (!processPath.empty())
{
if (zoneIndex == -1)
auto history = appZoneHistoryMap.find(processPath);
if (history != appZoneHistoryMap.end())
{
appZoneHistoryMap.erase(std::wstring{ appPath });
}
else
{
//TODO(stefan) provide correct uuid in the future
appZoneHistoryMap[std::wstring{ appPath }] = AppZoneHistoryData{ L"", static_cast<int>(zoneIndex) };
const auto& data = history->second;
if (data.zoneSetUuid == zoneSetId && data.deviceId == deviceId)
{
appZoneHistoryMap.erase(processPath);
return true;
}
}
return true;
}

return false;
}

bool FancyZonesData::SetAppLastZone(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, int zoneIndex)
{
auto processPath = get_process_path(window);
if (processPath.empty())
{
return false;
}

appZoneHistoryMap[processPath] = AppZoneHistoryData{ .zoneSetUuid = zoneSetId, .deviceId = deviceId, .zoneIndex = zoneIndex };
return true;
}

void FancyZonesData::SetActiveZoneSet(const std::wstring& deviceId, const std::wstring& uuid)
{
if (!uuid.empty() && deviceInfoMap.find(deviceId) != deviceInfoMap.end())
Expand Down Expand Up @@ -509,7 +528,7 @@ namespace JSONHelpers
DWORD i = 0;
while (RegEnumValueW(hkey, i++, value, &valueLength, nullptr, nullptr, reinterpret_cast<BYTE*>(&zoneIndex), &dataSize) == ERROR_SUCCESS)
{
appZoneHistoryMap[std::wstring{ value }] = AppZoneHistoryData{ L"", static_cast<int>(zoneIndex) }; //TODO(stefan) provide correct uuid in the future
appZoneHistoryMap[std::wstring{ value }] = AppZoneHistoryData{ .zoneSetUuid = L"", .deviceId = L"", .zoneIndex = static_cast<int>(zoneIndex) }; //TODO(stefan) provide correct uuid in the future

valueLength = ARRAYSIZE(value);
dataSize = sizeof(zoneIndex);
Expand Down Expand Up @@ -676,8 +695,9 @@ namespace JSONHelpers
json::JsonObject result{};

result.SetNamedValue(L"app-path", json::value(appZoneHistory.appPath));
result.SetNamedValue(L"zoneset-uuid", json::value(appZoneHistory.data.zoneSetUuid));
result.SetNamedValue(L"zone-index", json::value(appZoneHistory.data.zoneIndex));
result.SetNamedValue(L"device-id", json::value(appZoneHistory.data.deviceId));
result.SetNamedValue(L"zoneset-uuid", json::value(appZoneHistory.data.zoneSetUuid));

return result;
}
Expand All @@ -689,8 +709,9 @@ namespace JSONHelpers
AppZoneHistoryJSON result;

result.appPath = zoneSet.GetNamedString(L"app-path");
result.data.zoneSetUuid = zoneSet.GetNamedString(L"zoneset-uuid");
result.data.zoneIndex = static_cast<int>(zoneSet.GetNamedNumber(L"zone-index"));
result.data.deviceId = zoneSet.GetNamedString(L"device-id");
result.data.zoneSetUuid = zoneSet.GetNamedString(L"zoneset-uuid");

return result;
}
Expand Down
9 changes: 5 additions & 4 deletions src/modules/fancyzones/lib/JsonHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ namespace JSONHelpers

struct AppZoneHistoryData
{
std::wstring zoneSetUuid; //TODO(stefan): is this nessecary? It doesn't exist with registry impl.
std::wstring zoneSetUuid;
std::wstring deviceId;
int zoneIndex;
//TODO(stefan): Also, do we need DeviceID here? Do we want to support that - app history per monitor?
};

struct AppZoneHistoryJSON
Expand Down Expand Up @@ -197,8 +197,9 @@ namespace JSONHelpers

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

int GetAppLastZone(HWND window, PCWSTR appPath) const;
bool SetAppLastZone(HWND window, PCWSTR appPath, DWORD zoneIndex); //TODO(stefan): Missing zone uuid (pass as arg)
int GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const;
bool RemoveAppLastZone(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId);
bool SetAppLastZone(HWND window, const std::wstring& deviceId, const std::wstring& zoneSetId, int zoneIndex);

void SetActiveZoneSet(const std::wstring& deviceId, const std::wstring& uuid);

Expand Down
11 changes: 8 additions & 3 deletions src/modules/fancyzones/lib/ZoneWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,13 +491,18 @@ ZoneWindow::CycleActiveZoneSet(DWORD wparam) noexcept
IFACEMETHODIMP_(void)
ZoneWindow::SaveWindowProcessToZoneIndex(HWND window) noexcept
{
auto processPath = get_process_path(window);
if (!processPath.empty() && m_activeZoneSet)
if (m_activeZoneSet)
{
DWORD zoneIndex = static_cast<DWORD>(m_activeZoneSet->GetZoneIndexFromWindow(window));
if (zoneIndex != -1)
{
JSONHelpers::FancyZonesDataInstance().SetAppLastZone(window, processPath.data(), zoneIndex);
OLECHAR* guidString;
if (StringFromCLSID(m_activeZoneSet->Id(), &guidString) == S_OK)
{
JSONHelpers::FancyZonesDataInstance().SetAppLastZone(window, m_uniqueId, guidString, zoneIndex);
}

CoTaskMemFree(guidString);
}
}
}
Expand Down
17 changes: 0 additions & 17 deletions src/modules/fancyzones/tests/UnitTests/FancyZones.Spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,23 +321,6 @@ namespace FancyZonesUnitTests
Assert::IsFalse(m_fzCallback->InMoveSize());
}

TEST_METHOD(MoveSizeEndAppLastZoneTest)
{
const auto window = Mocks::WindowCreate(m_hInst);
const auto processPath = get_process_path(window);

Assert::AreEqual(-1, m_fancyZonesData.GetAppLastZone(window, processPath.c_str()));

m_fzCallback->MoveSizeEnd(window, POINT{ 0, 0 });
Assert::AreEqual(-1, m_fancyZonesData.GetAppLastZone(window, processPath.c_str()));

m_fancyZonesData.SetAppLastZone(window, processPath.c_str(), 1);
Assert::AreEqual(1, m_fancyZonesData.GetAppLastZone(window, processPath.c_str()));

m_fzCallback->MoveSizeEnd(window, POINT{ 0, 0 });
Assert::AreEqual(-1, m_fancyZonesData.GetAppLastZone(window, processPath.c_str()));
}

TEST_METHOD(OnKeyDownNothingPressed)
{
for (DWORD code = '0'; code <= '9'; code++)
Expand Down
Loading

0 comments on commit fd094a1

Please sign in to comment.