mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 17:42:45 +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;
|
void RegisterVirtualDesktopUpdates(std::vector<GUID>& ids) noexcept;
|
||||||
|
|
||||||
bool IsSplashScreen(HWND window);
|
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;
|
void OnEditorExitEvent() noexcept;
|
||||||
bool ProcessSnapHotkey() noexcept;
|
bool ShouldProcessSnapHotkey() noexcept;
|
||||||
|
|
||||||
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
|
std::vector<std::pair<HMONITOR, RECT>> GetRawMonitorData() noexcept;
|
||||||
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
|
std::vector<HMONITOR> GetMonitorsSorted() noexcept;
|
||||||
@ -323,35 +328,103 @@ FancyZones::VirtualDesktopInitialize() noexcept
|
|||||||
PostMessage(m_window, WM_PRIV_VD_INIT, 0, 0);
|
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
|
// IFancyZonesCallback
|
||||||
IFACEMETHODIMP_(void)
|
IFACEMETHODIMP_(void)
|
||||||
FancyZones::WindowCreated(HWND window) noexcept
|
FancyZones::WindowCreated(HWND window) noexcept
|
||||||
{
|
{
|
||||||
std::shared_lock readLock(m_lock);
|
std::shared_lock readLock(m_lock);
|
||||||
|
if (m_settings->GetSettings()->appLastZone_moveWindows && ShouldProcessNewWindow(window))
|
||||||
if (m_settings->GetSettings()->appLastZone_moveWindows && IsInterestingWindow(window, m_settings->GetSettings()->excludedAppsArray))
|
|
||||||
{
|
{
|
||||||
auto zoneWindow = m_workAreaHandler.GetWorkArea(window);
|
HMONITOR primary = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
|
||||||
if (zoneWindow)
|
HMONITOR active = primary;
|
||||||
{
|
|
||||||
const auto activeZoneSet = zoneWindow->ActiveZoneSet();
|
|
||||||
if (activeZoneSet)
|
|
||||||
{
|
|
||||||
auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();
|
|
||||||
|
|
||||||
wil::unique_cotaskmem_string guidString;
|
POINT cursorPosition{};
|
||||||
if (SUCCEEDED(StringFromCLSID(activeZoneSet->Id(), &guidString)))
|
if (GetCursorPos(&cursorPosition))
|
||||||
{
|
{
|
||||||
std::vector<int> zoneIndexSet = fancyZonesData.GetAppLastZoneIndexSet(window, zoneWindow->UniqueId(), guidString.get());
|
active = MonitorFromPoint(cursorPosition, MONITOR_DEFAULTTOPRIMARY);
|
||||||
if (zoneIndexSet.size() &&
|
}
|
||||||
!IsSplashScreen(window) &&
|
|
||||||
!fancyZonesData.IsAnotherWindowOfApplicationInstanceZoned(window, zoneWindow->UniqueId()))
|
const bool primaryActive = (primary == active);
|
||||||
{
|
std::pair<winrt::com_ptr<IZoneWindow>, std::vector<int>> appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, primaryActive);
|
||||||
m_windowMoveHandler.MoveWindowIntoZoneByIndexSet(window, zoneIndexSet, zoneWindow);
|
if (!appZoneHistoryInfo.second.empty())
|
||||||
fancyZonesData.UpdateProcessIdToHandleMap(window, zoneWindow->UniqueId());
|
{
|
||||||
}
|
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))
|
else if ((info->vkCode == VK_RIGHT) || (info->vkCode == VK_LEFT))
|
||||||
{
|
{
|
||||||
if (ProcessSnapHotkey())
|
if (ShouldProcessSnapHotkey())
|
||||||
{
|
{
|
||||||
Trace::FancyZones::OnKeyDown(info->vkCode, win, ctrl, false /*inMoveSize*/);
|
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
|
// 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)
|
if (m_settings->GetSettings()->overrideSnapHotkeys)
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,12 @@
|
|||||||
#include <common/common.h>
|
#include <common/common.h>
|
||||||
#include <common/dpi_aware.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*);
|
typedef BOOL(WINAPI* GetDpiForMonitorInternalFunc)(HMONITOR, UINT, UINT*, UINT*);
|
||||||
UINT GetDpiForMonitor(HMONITOR monitor) noexcept
|
UINT GetDpiForMonitor(HMONITOR monitor) noexcept
|
||||||
{
|
{
|
||||||
@ -157,7 +163,11 @@ bool IsInterestingWindow(HWND window, const std::vector<std::wstring>& excludedA
|
|||||||
{
|
{
|
||||||
return false;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user