[FancyZones]Fix moving windows on other virtual desktops (#29059)

* clean up obsolete vd check

* clean up

* replace virtual desktop id usage

* check current vd
This commit is contained in:
Seraphima Zykova
2023-10-23 16:13:24 +02:00
committed by GitHub
parent 812b343776
commit 78a94aecb9
4 changed files with 25 additions and 166 deletions

View File

@@ -156,9 +156,9 @@ private:
void SyncVirtualDesktops() noexcept;
void UpdateHotkey(int hotkeyId, const PowerToysSettings::HotkeyObject& hotkeyObject, bool enable) noexcept;
bool MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept;
bool MoveToAppLastZone(HWND window, HMONITOR monitor, GUID currentVirtualDesktop) noexcept;
void RefreshLayouts() noexcept;
bool ShouldProcessSnapHotkey(DWORD vkCode) noexcept;
void ApplyQuickLayout(int key) noexcept;
@@ -257,7 +257,6 @@ FancyZones::Run() noexcept
}
});
VirtualDesktop::instance().UpdateVirtualDesktopId();
SyncVirtualDesktops();
// id format of applied-layouts and app-zone-history was changed in 0.60
@@ -332,7 +331,7 @@ void FancyZones::MoveSizeEnd()
}
}
bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept
bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor, GUID currentVirtualDesktop) noexcept
{
const auto& workAreas = m_workAreaConfiguration.GetAllWorkAreas();
WorkArea* workArea{ nullptr };
@@ -343,7 +342,7 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept
if (workAreas.contains(monitor))
{
workArea = workAreas.at(monitor).get();
if (workArea)
if (workArea && workArea->UniqueId().virtualDesktopId == currentVirtualDesktop)
{
indexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, workArea->UniqueId(), workArea->GetLayoutId());
}
@@ -357,7 +356,7 @@ bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR monitor) noexcept
{
for (const auto& [_, secondaryWorkArea] : workAreas)
{
if (secondaryWorkArea)
if (secondaryWorkArea && secondaryWorkArea->UniqueId().virtualDesktopId == currentVirtualDesktop)
{
indexes = AppZoneHistory::instance().GetAppLastZoneIndexSet(window, secondaryWorkArea->UniqueId(), secondaryWorkArea->GetLayoutId());
workArea = secondaryWorkArea.get();
@@ -412,27 +411,28 @@ void FancyZones::WindowCreated(HWND window) noexcept
}
bool windowMovedToZone = false;
auto currentVirtualDesktop = VirtualDesktop::instance().GetCurrentVirtualDesktopIdFromRegistry();
if (moveToAppLastZone)
{
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
{
windowMovedToZone = MoveToAppLastZone(window, nullptr);
windowMovedToZone = MoveToAppLastZone(window, nullptr, currentVirtualDesktop);
}
else
{
// Search application history on currently active monitor.
windowMovedToZone = MoveToAppLastZone(window, active);
windowMovedToZone = MoveToAppLastZone(window, active, currentVirtualDesktop);
if (!windowMovedToZone && primary != active)
{
// Search application history on primary monitor.
windowMovedToZone = MoveToAppLastZone(window, primary);
windowMovedToZone = MoveToAppLastZone(window, primary, currentVirtualDesktop);
}
if (!windowMovedToZone)
{
// Search application history on remaining monitors.
windowMovedToZone = MoveToAppLastZone(window, nullptr);
windowMovedToZone = MoveToAppLastZone(window, nullptr, currentVirtualDesktop);
}
}
}
@@ -641,12 +641,10 @@ LRESULT FancyZones::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lpa
}
else if (message == WM_PRIV_INIT)
{
VirtualDesktop::instance().UpdateVirtualDesktopId();
OnDisplayChange(DisplayChangeType::Initialization);
}
else if (message == WM_PRIV_VD_SWITCH)
{
VirtualDesktop::instance().UpdateVirtualDesktopId();
OnDisplayChange(DisplayChangeType::VirtualDesktop);
}
else if (message == WM_PRIV_EDITOR)
@@ -745,10 +743,10 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
bool FancyZones::AddWorkArea(HMONITOR monitor, const FancyZonesDataTypes::WorkAreaId& id) noexcept
{
wil::unique_cotaskmem_string virtualDesktopIdStr;
if (!SUCCEEDED(StringFromCLSID(VirtualDesktop::instance().GetCurrentVirtualDesktopId(), &virtualDesktopIdStr)))
auto virtualDesktopIdStr = FancyZonesUtils::GuidToString(id.virtualDesktopId);
if (virtualDesktopIdStr)
{
Logger::debug(L"Add new work area on virtual desktop {}", virtualDesktopIdStr.get());
Logger::debug(L"Add new work area on virtual desktop {}", virtualDesktopIdStr.value());
}
FancyZonesUtils::Rect rect{};
@@ -794,11 +792,12 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept
Logger::debug(L"Update work areas, update windows positions: {}", updateWindowPositions);
m_workAreaConfiguration.Clear();
auto currentVirtualDesktop = VirtualDesktop::instance().GetCurrentVirtualDesktopIdFromRegistry();
if (FancyZonesSettings::settings().spanZonesAcrossMonitors)
{
FancyZonesDataTypes::WorkAreaId workAreaId;
workAreaId.virtualDesktopId = VirtualDesktop::instance().GetCurrentVirtualDesktopId();
workAreaId.virtualDesktopId = currentVirtualDesktop;
workAreaId.monitorId = { .deviceId = { .id = ZonedWindowProperties::MultiMonitorName, .instanceId = ZonedWindowProperties::MultiMonitorInstance } };
AddWorkArea(nullptr, workAreaId);
@@ -809,7 +808,7 @@ void FancyZones::UpdateWorkAreas(bool updateWindowPositions) noexcept
for (const auto& monitor : monitors)
{
FancyZonesDataTypes::WorkAreaId workAreaId;
workAreaId.virtualDesktopId = VirtualDesktop::instance().GetCurrentVirtualDesktopId();
workAreaId.virtualDesktopId = currentVirtualDesktop;
workAreaId.monitorId = monitor;
AddWorkArea(monitor.monitor, workAreaId);
@@ -906,7 +905,7 @@ void FancyZones::SyncVirtualDesktops() noexcept
// that case (00000000-0000-0000-0000-000000000000).
auto lastUsed = LastUsedVirtualDesktop::instance().GetId();
auto current = VirtualDesktop::instance().GetCurrentVirtualDesktopId();
auto current = VirtualDesktop::instance().GetCurrentVirtualDesktopIdFromRegistry();
auto guids = VirtualDesktop::instance().GetVirtualDesktopIdsFromRegistry();
if (current != lastUsed)

View File

@@ -278,32 +278,7 @@ void AppZoneHistory::LoadData()
void AppZoneHistory::SaveData()
{
bool dirtyFlag = false;
std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>> updatedHistory;
for (const auto& [path, dataVector] : m_history)
{
auto updatedVector = dataVector;
for (auto& data : updatedVector)
{
if (!VirtualDesktop::instance().IsVirtualDesktopIdSavedInRegistry(data.workAreaId.virtualDesktopId))
{
data.workAreaId.virtualDesktopId = GUID_NULL;
dirtyFlag = true;
}
}
updatedHistory.insert(std::make_pair(path, updatedVector));
}
if (dirtyFlag)
{
json::to_file(AppZoneHistoryFileName(), JsonUtils::SerializeJson(updatedHistory));
}
else
{
json::to_file(AppZoneHistoryFileName(), JsonUtils::SerializeJson(m_history));
}
json::to_file(AppZoneHistoryFileName(), JsonUtils::SerializeJson(m_history));
}
void AppZoneHistory::AdjustWorkAreaIds(const std::vector<FancyZonesDataTypes::MonitorId>& ids)

View File

@@ -96,14 +96,14 @@ VirtualDesktop& VirtualDesktop::instance()
return self;
}
std::optional<GUID> VirtualDesktop::GetCurrentVirtualDesktopIdFromRegistry() const
GUID VirtualDesktop::GetCurrentVirtualDesktopIdFromRegistry() const
{
// On newer Windows builds, the current virtual desktop is persisted to
// a totally different reg key. Look there first.
std::optional<GUID> desktopId = NewGetCurrentDesktopId();
if (desktopId.has_value())
{
return desktopId;
return desktopId.value();
}
// Explorer persists current virtual desktop identifier to registry on a per session basis, but only
@@ -112,7 +112,7 @@ std::optional<GUID> VirtualDesktop::GetCurrentVirtualDesktopIdFromRegistry() con
desktopId = GetDesktopIdFromCurrentSession();
if (desktopId.has_value())
{
return desktopId;
return desktopId.value();
}
// Fallback scenario is to get array of virtual desktops stored in registry, but not kept per session.
@@ -128,7 +128,7 @@ std::optional<GUID> VirtualDesktop::GetCurrentVirtualDesktopIdFromRegistry() con
}
}
return std::nullopt;
return GUID_NULL;
}
std::optional<std::vector<GUID>> VirtualDesktop::GetVirtualDesktopIdsFromRegistry(HKEY hKey) const
@@ -169,25 +169,6 @@ std::optional<std::vector<GUID>> VirtualDesktop::GetVirtualDesktopIdsFromRegistr
return GetVirtualDesktopIdsFromRegistry(GetVirtualDesktopsRegKey());
}
bool VirtualDesktop::IsVirtualDesktopIdSavedInRegistry(GUID id) const
{
auto ids = GetVirtualDesktopIdsFromRegistry();
if (!ids.has_value())
{
return false;
}
for (const auto& regId : *ids)
{
if (regId == id)
{
return true;
}
}
return false;
}
bool VirtualDesktop::IsWindowOnCurrentDesktop(HWND window) const
{
BOOL isWindowOnCurrentDesktop = false;
@@ -199,47 +180,6 @@ bool VirtualDesktop::IsWindowOnCurrentDesktop(HWND window) const
return isWindowOnCurrentDesktop;
}
std::optional<GUID> VirtualDesktop::GetDesktopId(HWND window) const
{
GUID id;
BOOL isWindowOnCurrentDesktop = false;
if (m_vdManager && m_vdManager->IsWindowOnCurrentVirtualDesktop(window, &isWindowOnCurrentDesktop) == S_OK && isWindowOnCurrentDesktop)
{
// Filter windows such as Windows Start Menu, Task Switcher, etc.
if (m_vdManager->GetWindowDesktopId(window, &id) == S_OK)
{
return id;
}
}
return std::nullopt;
}
std::vector<std::pair<HWND, GUID>> VirtualDesktop::GetWindowsRelatedToDesktops() const
{
using result_t = std::vector<HWND>;
result_t windows;
auto callback = [](HWND window, LPARAM data) -> BOOL {
result_t& result = *reinterpret_cast<result_t*>(data);
result.push_back(window);
return TRUE;
};
EnumWindows(callback, reinterpret_cast<LPARAM>(&windows));
std::vector<std::pair<HWND, GUID>> result;
for (auto window : windows)
{
auto desktop = GetDesktopId(window);
if (desktop.has_value())
{
result.push_back({ window, *desktop });
}
}
return result;
}
std::vector<HWND> VirtualDesktop::GetWindowsFromCurrentDesktop() const
{
using result_t = std::vector<HWND>;
@@ -263,49 +203,4 @@ std::vector<HWND> VirtualDesktop::GetWindowsFromCurrentDesktop() const
}
return result;
}
GUID VirtualDesktop::GetCurrentVirtualDesktopId() const noexcept
{
return m_currentVirtualDesktopId;
}
void VirtualDesktop::UpdateVirtualDesktopId() noexcept
{
auto currentVirtualDesktopId = GetCurrentVirtualDesktopIdFromRegistry();
if (currentVirtualDesktopId.has_value())
{
m_currentVirtualDesktopId = currentVirtualDesktopId.value();
}
else
{
m_currentVirtualDesktopId = GUID_NULL;
}
Trace::VirtualDesktopChanged();
}
std::optional<GUID> VirtualDesktop::GetDesktopIdByTopLevelWindows() const
{
using result_t = std::vector<HWND>;
result_t windows;
auto callback = [](HWND window, LPARAM data) -> BOOL {
result_t& result = *reinterpret_cast<result_t*>(data);
result.push_back(window);
return TRUE;
};
EnumWindows(callback, reinterpret_cast<LPARAM>(&windows));
for (const auto window : windows)
{
std::optional<GUID> id = GetDesktopId(window);
if (id.has_value())
{
// Otherwise keep checking other windows
return *id;
}
}
return std::nullopt;
}
}

View File

@@ -5,29 +5,19 @@ class VirtualDesktop
public:
static VirtualDesktop& instance();
// saved values
GUID GetCurrentVirtualDesktopId() const noexcept;
void UpdateVirtualDesktopId() noexcept;
// IVirtualDesktopManager
bool IsWindowOnCurrentDesktop(HWND window) const;
std::optional<GUID> GetDesktopId(HWND window) const;
std::optional<GUID> GetDesktopIdByTopLevelWindows() const;
std::vector<std::pair<HWND, GUID>> GetWindowsRelatedToDesktops() const;
std::vector<HWND> GetWindowsFromCurrentDesktop() const;
// registry
std::optional<GUID> GetCurrentVirtualDesktopIdFromRegistry() const;
GUID GetCurrentVirtualDesktopIdFromRegistry() const;
std::optional<std::vector<GUID>> GetVirtualDesktopIdsFromRegistry() const;
bool IsVirtualDesktopIdSavedInRegistry(GUID id) const;
private:
VirtualDesktop();
~VirtualDesktop();
IVirtualDesktopManager* m_vdManager{nullptr};
GUID m_currentVirtualDesktopId{};
std::optional<std::vector<GUID>> GetVirtualDesktopIdsFromRegistry(HKEY hKey) const;
};