mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-08 01:52:52 +08:00
Handle scenario with only primary desktop and no desktop switch in current session. (#2339)
* Handle scenario with only primary desktop and no desktop swithc in current session. * Add scoped lock when changing current desktop id. Address PR comments. * Explain purpose of UpdatePrimaryDesktopData method. * Fix typo in documentation.
This commit is contained in:
parent
2db98715cc
commit
648f3abcbd
@ -5,7 +5,6 @@
|
||||
#include "FancyZones.h"
|
||||
#include "lib/Settings.h"
|
||||
#include "lib/ZoneWindow.h"
|
||||
#include "lib/RegistryHelpers.h"
|
||||
#include "lib/JsonHelpers.h"
|
||||
#include "lib/ZoneSet.h"
|
||||
#include "trace.h"
|
||||
@ -642,15 +641,25 @@ void FancyZones::OnDisplayChange(DisplayChangeType changeType) noexcept
|
||||
// then this value will be empty. This means loading the first virtual desktop's configuration can be
|
||||
// funky the first time we load up at boot since the user will not have switched virtual desktops yet.
|
||||
GUID currentVirtualDesktopId{};
|
||||
if (SUCCEEDED(RegistryHelpers::GetCurrentVirtualDesktop(¤tVirtualDesktopId)))
|
||||
if (VirtualDesktopUtils::GetCurrentVirtualDesktopId(¤tVirtualDesktopId))
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_currentVirtualDesktopId = currentVirtualDesktopId;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Use the previous "Desktop 1" fallback
|
||||
// Need to maintain a map of desktop name to virtual desktop uuid
|
||||
std::vector<GUID> ids{};
|
||||
if (VirtualDesktopUtils::GetVirtualDekstopIds(m_virtualDesktopsRegKey, ids) && !ids.empty())
|
||||
{
|
||||
std::unique_lock writeLock(m_lock);
|
||||
m_currentVirtualDesktopId = ids[0];
|
||||
wil::unique_cotaskmem_string id;
|
||||
if (changeType == DisplayChangeType::Initialization &&
|
||||
SUCCEEDED_LOG(StringFromCLSID(m_currentVirtualDesktopId, &id)))
|
||||
{
|
||||
JSONHelpers::FancyZonesDataInstance().UpdatePrimaryDesktopData(id.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1132,28 +1141,12 @@ void FancyZones::HandleVirtualDesktopUpdates(HANDLE fancyZonesDestroyedEvent) no
|
||||
// if fancyZonesDestroyedEvent is signalized or WaitForMultipleObjects failed, terminate thread execution
|
||||
return;
|
||||
}
|
||||
DWORD bufferCapacity;
|
||||
const WCHAR* key = L"VirtualDesktopIDs";
|
||||
// request regkey binary buffer capacity only
|
||||
if (RegQueryValueExW(m_virtualDesktopsRegKey, key, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS)
|
||||
std::vector<GUID> ids{};
|
||||
if (VirtualDesktopUtils::GetVirtualDekstopIds(m_virtualDesktopsRegKey, ids))
|
||||
{
|
||||
return;
|
||||
std::unordered_set<GUID> idSet(std::begin(ids), std::end(ids));
|
||||
RegisterVirtualDesktopUpdates(idSet);
|
||||
}
|
||||
std::unique_ptr<BYTE[]> buffer = std::make_unique<BYTE[]>(bufferCapacity);
|
||||
// request regkey binary content
|
||||
if (RegQueryValueExW(m_virtualDesktopsRegKey, key, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
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.insert(*guid);
|
||||
}
|
||||
RegisterVirtualDesktopUpdates(temp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,6 @@
|
||||
<ClInclude Include="FancyZones.h" />
|
||||
<ClInclude Include="JsonHelpers.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="RegistryHelpers.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="Settings.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
|
@ -30,9 +30,6 @@
|
||||
<ClInclude Include="FancyZones.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RegistryHelpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Settings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "pch.h"
|
||||
#include "JsonHelpers.h"
|
||||
#include "RegistryHelpers.h"
|
||||
#include "ZoneSet.h"
|
||||
#include "trace.h"
|
||||
|
||||
@ -37,6 +36,7 @@ namespace
|
||||
|
||||
const wchar_t* FANCY_ZONES_DATA_FILE = L"zones-settings.json";
|
||||
const wchar_t* DEFAULT_GUID = L"{00000000-0000-0000-0000-000000000000}";
|
||||
const wchar_t* REG_SETTINGS = L"Software\\SuperFancyZones";
|
||||
|
||||
std::wstring ExtractVirtualDesktopId(const std::wstring& deviceId)
|
||||
{
|
||||
@ -321,6 +321,46 @@ namespace JSONHelpers
|
||||
}
|
||||
}
|
||||
|
||||
void FancyZonesData::UpdatePrimaryDesktopData(const std::wstring& desktopId)
|
||||
{
|
||||
// Explorer persists current virtual desktop identifier to registry on a per session basis,
|
||||
// but only after first virtual desktop switch happens. If the user hasn't switched virtual
|
||||
// desktops in this session value in registry will be empty and we will use default GUID in
|
||||
// that case (00000000-0000-0000-0000-000000000000).
|
||||
// This method will go through all our persisted data with default GUID and update it with
|
||||
// valid one.
|
||||
auto replaceDesktopId = [&desktopId](const std::wstring& deviceId) {
|
||||
return deviceId.substr(0, deviceId.rfind('_') + 1) + desktopId;
|
||||
};
|
||||
std::scoped_lock lock{ dataLock };
|
||||
for (auto& [path, data] : appZoneHistoryMap)
|
||||
{
|
||||
if (ExtractVirtualDesktopId(data.deviceId) == DEFAULT_GUID)
|
||||
{
|
||||
data.deviceId = replaceDesktopId(data.deviceId);
|
||||
}
|
||||
}
|
||||
std::vector<std::wstring> toReplace{};
|
||||
for (const auto& [id, data] : deviceInfoMap)
|
||||
{
|
||||
if (ExtractVirtualDesktopId(id) == DEFAULT_GUID)
|
||||
{
|
||||
toReplace.push_back(id);
|
||||
}
|
||||
}
|
||||
for (const auto& id : toReplace)
|
||||
{
|
||||
auto mapEntry = deviceInfoMap.extract(id);
|
||||
mapEntry.key() = replaceDesktopId(id);
|
||||
deviceInfoMap.insert(std::move(mapEntry));
|
||||
}
|
||||
if (activeDeviceId == DEFAULT_GUID)
|
||||
{
|
||||
activeDeviceId = replaceDesktopId(activeDeviceId);
|
||||
}
|
||||
SaveFancyZonesData();
|
||||
}
|
||||
|
||||
int FancyZonesData::GetAppLastZoneIndex(HWND window, const std::wstring_view& deviceId, const std::wstring_view& zoneSetId) const
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
@ -640,7 +680,7 @@ namespace JSONHelpers
|
||||
{
|
||||
std::scoped_lock lock{ dataLock };
|
||||
wchar_t key[256];
|
||||
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", RegistryHelpers::REG_SETTINGS, L"Layouts");
|
||||
StringCchPrintf(key, ARRAYSIZE(key), L"%s\\%s", REG_SETTINGS, L"Layouts");
|
||||
HKEY hkey;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS)
|
||||
{
|
||||
|
@ -233,6 +233,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);
|
||||
void UpdatePrimaryDesktopData(const std::wstring& desktopId);
|
||||
|
||||
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);
|
||||
|
@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
namespace RegistryHelpers
|
||||
{
|
||||
static PCWSTR REG_SETTINGS = L"Software\\SuperFancyZones";
|
||||
static PCWSTR APP_ZONE_HISTORY_SUBKEY = L"AppZoneHistory";
|
||||
|
||||
inline HRESULT GetCurrentVirtualDesktop(_Out_ GUID* id)
|
||||
{
|
||||
*id = GUID_NULL;
|
||||
|
||||
DWORD sessionId;
|
||||
ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
|
||||
wchar_t sessionKeyPath[256]{};
|
||||
RETURN_IF_FAILED(
|
||||
StringCchPrintfW(
|
||||
sessionKeyPath,
|
||||
ARRAYSIZE(sessionKeyPath),
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops",
|
||||
sessionId));
|
||||
wil::unique_hkey key{};
|
||||
GUID value{};
|
||||
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD size = sizeof(value);
|
||||
if (RegQueryValueExW(key.get(), L"CurrentVirtualDesktop", 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*id = value;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
@ -7,6 +7,9 @@ namespace VirtualDesktopUtils
|
||||
const CLSID CLSID_ImmersiveShell = { 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 };
|
||||
const wchar_t GUID_EmptyGUID[] = L"{00000000-0000-0000-0000-000000000000}";
|
||||
|
||||
const wchar_t RegCurrentVirtualDesktop[] = L"CurrentVirtualDesktop";
|
||||
const wchar_t RegVirtualDesktopIds[] = L"VirtualDesktopIDs";
|
||||
|
||||
IServiceProvider* GetServiceProvider()
|
||||
{
|
||||
IServiceProvider* provider{ nullptr };
|
||||
@ -46,4 +49,57 @@ namespace VirtualDesktopUtils
|
||||
}
|
||||
return SUCCEEDED(CLSIDFromString(virtualDesktopId.c_str(), desktopId));
|
||||
}
|
||||
|
||||
bool GetCurrentVirtualDesktopId(GUID* desktopId)
|
||||
{
|
||||
DWORD sessionId;
|
||||
ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
|
||||
wchar_t sessionKeyPath[256]{};
|
||||
RETURN_IF_FAILED(
|
||||
StringCchPrintfW(
|
||||
sessionKeyPath,
|
||||
ARRAYSIZE(sessionKeyPath),
|
||||
L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SessionInfo\\%d\\VirtualDesktops",
|
||||
sessionId));
|
||||
|
||||
wil::unique_hkey key{};
|
||||
GUID value{};
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, sessionKeyPath, 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD size = sizeof(GUID);
|
||||
if (RegQueryValueExW(key.get(), RegCurrentVirtualDesktop, 0, nullptr, reinterpret_cast<BYTE*>(&value), &size) == ERROR_SUCCESS)
|
||||
{
|
||||
*desktopId = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetVirtualDekstopIds(HKEY hKey, std::vector<GUID>& ids)
|
||||
{
|
||||
DWORD bufferCapacity;
|
||||
// request regkey binary buffer capacity only
|
||||
if (RegQueryValueExW(hKey, RegVirtualDesktopIds, 0, nullptr, nullptr, &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<BYTE[]> buffer = std::make_unique<BYTE[]>(bufferCapacity);
|
||||
// request regkey binary content
|
||||
if (RegQueryValueExW(hKey, RegVirtualDesktopIds, 0, nullptr, buffer.get(), &bufferCapacity) != ERROR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const size_t guidSize = sizeof(GUID);
|
||||
std::vector<GUID> temp;
|
||||
temp.reserve(bufferCapacity / guidSize);
|
||||
for (size_t i = 0; i < bufferCapacity; i += guidSize)
|
||||
{
|
||||
GUID* guid = reinterpret_cast<GUID*>(buffer.get() + i);
|
||||
temp.push_back(*guid);
|
||||
}
|
||||
ids = std::move(temp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -6,4 +6,6 @@ namespace VirtualDesktopUtils
|
||||
{
|
||||
bool GetWindowDesktopId(HWND topLevelWindow, GUID* desktopId);
|
||||
bool GetZoneWindowDesktopId(IZoneWindow* zoneWindow, GUID* desktopId);
|
||||
bool GetCurrentVirtualDesktopId(GUID* desktopId);
|
||||
bool GetVirtualDekstopIds(HKEY hKey, std::vector<GUID>& ids);
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "lib/ZoneSet.h"
|
||||
#include "lib/RegistryHelpers.h"
|
||||
|
||||
#include <common/dpi_aware.h>
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "ZoneWindow.h"
|
||||
#include "trace.h"
|
||||
#include "util.h"
|
||||
#include "RegistryHelpers.h"
|
||||
|
||||
#include <ShellScalingApi.h>
|
||||
#include <mutex>
|
||||
|
Loading…
Reference in New Issue
Block a user