mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 01:08:18 +08:00
[FancyZones] Move window into last known position on active work area (if possible) (#4218)
* Move window into last known position on active work area (if possible) * Refactor code to avoid double checks * Address PR comments * Perform all HWND checks at one place * Improve handling of active/primary work area in app zone history * Address PR comments: naming, arguments checks * Rename some functions to increase readability * Implement special handling in 2+ monitor scenario * Minor naming change * Simplify * Improve readability * Remove blank line * Don't move away from secondary monitor if there is no app zone history * Update comment * FancyZonesEditor should not be zoned * Preserve width and height (if possible) when opening on active monitor * Maintain w/h whenever possible * Remove scaling, add window coordinates on active monitor top-left corner * If there is no app zone history on secondary screen, fallback to default windows behavior.
This commit is contained in:
parent
7f25e3ba97
commit
698e5ec6ea
@ -211,9 +211,14 @@ private:
|
||||
void RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept;
|
||||
|
||||
bool IsSplashScreen(HWND window);
|
||||
bool ShouldProcessNewWindow(HWND window) noexcept;
|
||||
std::vector<int> GetZoneIndexSetFromWorkAreaHistory(HWND window, winrt::com_ptr<IZoneWindow> workArea) noexcept;
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<int>> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& workAreaMap) noexcept;
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<int>> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept;
|
||||
void MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> zoneWindow, const std::vector<int>& zoneIndexSet) noexcept;
|
||||
|
||||
void OnEditorExitEvent() noexcept;
|
||||
bool ProcessSnapHotkey() noexcept;
|
||||
bool ShouldProcessSnapHotkey() noexcept;
|
||||
|
||||
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
|
||||
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
|
||||
@ -323,35 +328,103 @@ FancyZones::VirtualDesktopInitialize() noexcept
|
||||
PostMessage(m_window, WM_PRIV_VD_INIT, 0, 0);
|
||||
}
|
||||
|
||||
bool FancyZones::ShouldProcessNewWindow(HWND window) noexcept
|
||||
{
|
||||
// Avoid processing splash screens, already stamped (zoned) windows, or those windows
|
||||
// that belong to excluded applications list.
|
||||
if (IsSplashScreen(window) ||
|
||||
(reinterpret_cast<size_t>(::GetProp(window, MULTI_ZONE_STAMP)) != 0) ||
|
||||
!IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<int> FancyZones::GetZoneIndexSetFromWorkAreaHistory(
|
||||
HWND window, winrt::com_ptr<IZoneWindow> workArea) noexcept
|
||||
{
|
||||
const auto activeZoneSet = workArea->ActiveZoneSet();
|
||||
if (activeZoneSet)
|
||||
{
|
||||
wil::unique_cotaskmem_string zoneSetId;
|
||||
if (SUCCEEDED(StringFromCLSID(activeZoneSet->Id(), &zoneSetId)))
|
||||
{
|
||||
return JSONHelpers::FancyZonesDataInstance().GetAppLastZoneIndexSet(window, workArea->UniqueId(), zoneSetId.get());
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<int>> FancyZones::GetAppZoneHistoryInfo(
|
||||
HWND window,
|
||||
HMONITOR monitor,
|
||||
std::unordered_map<HMONITOR, winrt::com_ptr<IZoneWindow>>& workAreaMap) noexcept
|
||||
{
|
||||
if (workAreaMap.contains(monitor))
|
||||
{
|
||||
auto workArea = workAreaMap[monitor];
|
||||
workAreaMap.erase(monitor); // monitor processed, remove entry from the map
|
||||
return { workArea, GetZoneIndexSetFromWorkAreaHistory(window, workArea) };
|
||||
}
|
||||
return { nullptr, {} };
|
||||
}
|
||||
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<int>> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept
|
||||
{
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<int>> appZoneHistoryInfo{ nullptr, {} };
|
||||
auto workAreaMap = m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId);
|
||||
|
||||
// Search application history on currently active monitor.
|
||||
appZoneHistoryInfo = GetAppZoneHistoryInfo(window, monitor, workAreaMap);
|
||||
|
||||
if (isPrimaryMonitor && appZoneHistoryInfo.second.empty())
|
||||
{
|
||||
// No application history on primary monitor, search on remaining monitors.
|
||||
for (const auto& [monitor, workArea] : workAreaMap)
|
||||
{
|
||||
auto zoneIndexSet = GetZoneIndexSetFromWorkAreaHistory(window, workArea);
|
||||
if (!zoneIndexSet.empty())
|
||||
{
|
||||
return { workArea, zoneIndexSet };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return appZoneHistoryInfo;
|
||||
}
|
||||
|
||||
void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IZoneWindow> zoneWindow, const std::vector<int>& zoneIndexSet) noexcept
|
||||
{
|
||||
auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();
|
||||
if (!fancyZonesData.IsAnotherWindowOfApplicationInstanceZoned(window, zoneWindow->UniqueId()))
|
||||
{
|
||||
m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, zoneWindow);
|
||||
fancyZonesData.UpdateProcessIdToHandleMap(window, zoneWindow->UniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
// IFancyZonesCallback
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZones::WindowCreated(HWND window) noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
|
||||
if (m_settings->GetSettings()->appLastZone_moveWindows && IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
|
||||
if (m_settings->GetSettings()->appLastZone_moveWindows && ShouldProcessNewWindow(window))
|
||||
{
|
||||
auto zoneWindow = m_workAreaHandler.GetWorkArea(window);
|
||||
if (zoneWindow)
|
||||
{
|
||||
const auto activeZoneSet = zoneWindow->ActiveZoneSet();
|
||||
if (activeZoneSet)
|
||||
{
|
||||
auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();
|
||||
HMONITOR primary = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
|
||||
HMONITOR active = primary;
|
||||
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED(StringFromCLSID(activeZoneSet->Id(), &guidString)))
|
||||
{
|
||||
std::vector<int> zoneIndexSet = fancyZonesData.GetAppLastZoneIndexSet(window, zoneWindow->UniqueId(), guidString.get());
|
||||
if (zoneIndexSet.size() &&
|
||||
!IsSplashScreen(window) &&
|
||||
!fancyZonesData.IsAnotherWindowOfApplicationInstanceZoned(window, zoneWindow->UniqueId()))
|
||||
{
|
||||
m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, zoneWindow);
|
||||
fancyZonesData.UpdateProcessIdToHandleMap(window, zoneWindow->UniqueId());
|
||||
}
|
||||
}
|
||||
}
|
||||
POINT cursorPosition{};
|
||||
if (GetCursorPos(&cursorPosition))
|
||||
{
|
||||
active = MonitorFromPoint(cursorPosition, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
|
||||
const bool primaryActive = (primary == active);
|
||||
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<int>> appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, primaryActive);
|
||||
if (!appZoneHistoryInfo.second.empty())
|
||||
{
|
||||
MoveWindowIntoZone(window, appZoneHistoryInfo.first, appZoneHistoryInfo.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -379,7 +452,7 @@ FancyZones::OnKeyDown(PKBDLLHOOKSTRUCT info) noexcept
|
||||
}
|
||||
else if ((info->vkCode == VK_RIGHT) || (info->vkCode == VK_LEFT))
|
||||
{
|
||||
if (ProcessSnapHotkey())
|
||||
if (ShouldProcessSnapHotkey())
|
||||
{
|
||||
Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/);
|
||||
// Win+Left, Win+Right will cycle through Zones in the active ZoneSet when WM_PRIV_LOWLEVELKB's handled
|
||||
@ -904,7 +977,7 @@ void FancyZones::OnEditorExitEvent() noexcept
|
||||
}
|
||||
}
|
||||
|
||||
bool FancyZones::ProcessSnapHotkey() noexcept
|
||||
bool FancyZones::ShouldProcessSnapHotkey() noexcept
|
||||
{
|
||||
if (m_settings->GetSettings()->overrideSnapHotkeys)
|
||||
{
|
||||
|
@ -4,6 +4,12 @@
|
||||
#include <common/common.h>
|
||||
#include <common/dpi_aware.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t POWER_TOYS_APP_POWER_LAUCHER[] = L"POWERLAUNCHER.EXE";
|
||||
const wchar_t POWER_TOYS_APP_FANCY_ZONES_EDITOR[] = L"FANCYZONESEDITOR.EXE";
|
||||
}
|
||||
|
||||
typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*);
|
||||
UINT GetDpiForMonitor(HMONITOR monitor) noexcept
|
||||
{
|
||||
@ -157,7 +163,11 @@ bool IsInterestingWindow(HWND window, const std::vector<std::wstring>& excludedA
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (find_app_name_in_path(filtered.process_path, { L"POWERLAUNCHER.EXE" }))
|
||||
if (find_app_name_in_path(filtered.process_path, { POWER_TOYS_APP_POWER_LAUCHER }))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (find_app_name_in_path(filtered.process_path, { POWER_TOYS_APP_FANCY_ZONES_EDITOR }))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user