mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 19:27:56 +01:00
[Fancy Zones] Restore Console Applications (#12905)
This commit is contained in:
@@ -157,8 +157,9 @@ private:
|
||||
|
||||
void OnSettingsChanged() noexcept;
|
||||
|
||||
std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept;
|
||||
std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& workAreaMap) noexcept;
|
||||
void MoveWindowIntoZone(HWND window, winrt::com_ptr<IWorkArea> zoneWindow, const ZoneIndexSet& zoneIndexSet) noexcept;
|
||||
bool MoveToAppLastZone(HWND window, HMONITOR active, HMONITOR primary) noexcept;
|
||||
|
||||
void OnEditorExitEvent() noexcept;
|
||||
void UpdateZoneSets() noexcept;
|
||||
@@ -266,40 +267,33 @@ FancyZones::VirtualDesktopChanged() noexcept
|
||||
PostMessage(m_window, WM_PRIV_VD_SWITCH, 0, 0);
|
||||
}
|
||||
|
||||
std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept
|
||||
std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map<HMONITOR, winrt::com_ptr<IWorkArea>>& workAreaMap) noexcept
|
||||
{
|
||||
std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> appZoneHistoryInfo{ nullptr, {} };
|
||||
auto workAreaMap = m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId);
|
||||
if (workAreaMap.empty())
|
||||
if (monitor)
|
||||
{
|
||||
Logger::debug(L"No work area for the current desktop.");
|
||||
}
|
||||
|
||||
// Search application history on currently active monitor.
|
||||
if (workAreaMap.contains(monitor))
|
||||
{
|
||||
auto workArea = workAreaMap[monitor];
|
||||
appZoneHistoryInfo = { workArea, workArea->GetWindowZoneIndexes(window) };
|
||||
if (workAreaMap.contains(monitor))
|
||||
{
|
||||
auto workArea = workAreaMap.at(monitor);
|
||||
return std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet>{ workArea, workArea->GetWindowZoneIndexes(window) };
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::debug(L"No work area for the currently active monitor.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::debug(L"No work area for the currently active monitor.");
|
||||
}
|
||||
|
||||
if (isPrimaryMonitor && appZoneHistoryInfo.second.empty())
|
||||
{
|
||||
// No application history on primary monitor, search on remaining monitors.
|
||||
for (const auto& [monitor, workArea] : workAreaMap)
|
||||
{
|
||||
auto zoneIndexSet = workArea->GetWindowZoneIndexes(window);
|
||||
if (!zoneIndexSet.empty())
|
||||
{
|
||||
return { workArea, zoneIndexSet };
|
||||
return std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet>{ workArea, zoneIndexSet };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return appZoneHistoryInfo;
|
||||
|
||||
return std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet>{ nullptr, {} };
|
||||
}
|
||||
|
||||
void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IWorkArea> zoneWindow, const ZoneIndexSet& zoneIndexSet) noexcept
|
||||
@@ -313,62 +307,108 @@ void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr<IWorkArea> zoneW
|
||||
}
|
||||
}
|
||||
|
||||
bool FancyZones::MoveToAppLastZone(HWND window, HMONITOR active, HMONITOR primary) noexcept
|
||||
{
|
||||
auto workAreaMap = m_workAreaHandler.GetWorkAreasByDesktopId(m_currentDesktopId);
|
||||
if (workAreaMap.empty())
|
||||
{
|
||||
Logger::trace(L"No work area for the current desktop.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search application history on currently active monitor.
|
||||
std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, workAreaMap);
|
||||
|
||||
// No application history on currently active monitor
|
||||
if (appZoneHistoryInfo.second.empty())
|
||||
{
|
||||
// Search application history on primary monitor.
|
||||
appZoneHistoryInfo = GetAppZoneHistoryInfo(window, primary, workAreaMap);
|
||||
}
|
||||
|
||||
// No application history on currently active and primary monitors
|
||||
if (appZoneHistoryInfo.second.empty())
|
||||
{
|
||||
// Search application history on remaining monitors.
|
||||
appZoneHistoryInfo = GetAppZoneHistoryInfo(window, nullptr, workAreaMap);
|
||||
}
|
||||
|
||||
if (!appZoneHistoryInfo.second.empty())
|
||||
{
|
||||
MoveWindowIntoZone(window, appZoneHistoryInfo.first, appZoneHistoryInfo.second);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::trace(L"App zone history is empty for the processing window on a current virtual desktop");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FancyZones::WindowCreated(HWND window) noexcept
|
||||
{
|
||||
auto desktopId = m_virtualDesktop.GetWindowDesktopId(window);
|
||||
if (desktopId.has_value() && *desktopId != m_currentDesktopId)
|
||||
const bool moveToAppLastZone = m_settings->GetSettings()->appLastZone_moveWindows;
|
||||
const bool openOnActiveMonitor = m_settings->GetSettings()->openWindowOnActiveMonitor;
|
||||
if (!moveToAppLastZone && !openOnActiveMonitor)
|
||||
{
|
||||
// Nothing to do here then.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_virtualDesktop.IsWindowOnCurrentDesktop(window))
|
||||
{
|
||||
// Switch between virtual desktops results with posting same windows messages that also indicate
|
||||
// creation of new window. We need to check if window being processed is on currently active desktop.
|
||||
return;
|
||||
}
|
||||
|
||||
const bool moveToAppLastZone = m_settings->GetSettings()->appLastZone_moveWindows;
|
||||
const bool openOnActiveMonitor = m_settings->GetSettings()->openWindowOnActiveMonitor;
|
||||
|
||||
// Avoid processing splash screens, already stamped (zoned) windows, or those windows
|
||||
// that belong to excluded applications list.
|
||||
const bool isSplashScreen = FancyZonesUtils::IsSplashScreen(window);
|
||||
const bool isZoned = reinterpret_cast<ZoneIndex>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)) != 0;
|
||||
const bool isCandidateForLastKnownZone = FancyZonesUtils::IsCandidateForLastKnownZone(window, m_settings->GetSettings()->excludedAppsArray);
|
||||
const bool shouldProcessNewWindow = !isSplashScreen && !isZoned && isCandidateForLastKnownZone;
|
||||
|
||||
if ((moveToAppLastZone || openOnActiveMonitor) && shouldProcessNewWindow)
|
||||
if (isSplashScreen)
|
||||
{
|
||||
HMONITOR primary = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
|
||||
HMONITOR active = primary;
|
||||
return;
|
||||
}
|
||||
|
||||
POINT cursorPosition{};
|
||||
if (GetCursorPos(&cursorPosition))
|
||||
{
|
||||
active = MonitorFromPoint(cursorPosition, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
const bool windowMinimized = IsIconic(window);
|
||||
if (windowMinimized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool windowZoned{ false };
|
||||
if (moveToAppLastZone)
|
||||
{
|
||||
const bool primaryActive = (primary == active);
|
||||
std::pair<winrt::com_ptr<IWorkArea>, ZoneIndexSet> appZoneHistoryInfo = GetAppZoneHistoryInfo(window, active, primaryActive);
|
||||
|
||||
if (!appZoneHistoryInfo.second.empty())
|
||||
{
|
||||
const bool windowMinimized = IsIconic(window);
|
||||
if (!windowMinimized)
|
||||
{
|
||||
MoveWindowIntoZone(window, appZoneHistoryInfo.first, appZoneHistoryInfo.second);
|
||||
windowZoned = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::warn(L"App zone history is empty for the processing window on a current virtual desktop");
|
||||
}
|
||||
}
|
||||
const bool isZoned = reinterpret_cast<ZoneIndex>(::GetProp(window, ZonedWindowProperties::PropertyMultipleZoneID)) != 0;
|
||||
if (isZoned)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!windowZoned && openOnActiveMonitor)
|
||||
{
|
||||
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] { MonitorUtils::OpenWindowOnActiveMonitor(window, active); } }).wait();
|
||||
}
|
||||
const bool isCandidateForLastKnownZone = FancyZonesUtils::IsCandidateForLastKnownZone(window, m_settings->GetSettings()->excludedAppsArray);
|
||||
if (!isCandidateForLastKnownZone)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
HMONITOR primary = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
|
||||
HMONITOR active = primary;
|
||||
|
||||
POINT cursorPosition{};
|
||||
if (GetCursorPos(&cursorPosition))
|
||||
{
|
||||
active = MonitorFromPoint(cursorPosition, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
|
||||
bool movedToAppLastZone = false;
|
||||
if (moveToAppLastZone)
|
||||
{
|
||||
movedToAppLastZone = MoveToAppLastZone(window, active, primary);
|
||||
}
|
||||
|
||||
// Open on active monitor if window wasn't zoned
|
||||
if (openOnActiveMonitor && !movedToAppLastZone)
|
||||
{
|
||||
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] { MonitorUtils::OpenWindowOnActiveMonitor(window, active); } }).wait();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +210,28 @@ std::optional<std::vector<GUID>> VirtualDesktop::GetVirtualDesktopIds() const
|
||||
return GetVirtualDesktopIds(GetVirtualDesktopsRegKey());
|
||||
}
|
||||
|
||||
bool VirtualDesktop::IsWindowOnCurrentDesktop(HWND window) const
|
||||
{
|
||||
std::optional<GUID> id = GetDesktopId(window);
|
||||
return id.has_value();
|
||||
}
|
||||
|
||||
std::optional<GUID> VirtualDesktop::GetDesktopId(HWND window) const
|
||||
{
|
||||
GUID id;
|
||||
BOOL isWindowOnCurrentDesktop = false;
|
||||
if (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 && id != GUID_NULL)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<GUID> VirtualDesktop::GetDesktopIdByTopLevelWindows() const
|
||||
{
|
||||
using result_t = std::vector<HWND>;
|
||||
@@ -222,16 +244,13 @@ std::optional<GUID> VirtualDesktop::GetDesktopIdByTopLevelWindows() const
|
||||
};
|
||||
EnumWindows(callback, reinterpret_cast<LPARAM>(&result));
|
||||
|
||||
GUID id;
|
||||
BOOL isWindowOnCurrentDesktop = false;
|
||||
for (const auto window : result)
|
||||
{
|
||||
if (m_vdManager->IsWindowOnCurrentVirtualDesktop(window, &isWindowOnCurrentDesktop) == ERROR_SUCCESS && isWindowOnCurrentDesktop)
|
||||
std::optional<GUID> id = GetDesktopId(window);
|
||||
if (id.has_value())
|
||||
{
|
||||
if (m_vdManager->GetWindowDesktopId(window, &id) == ERROR_SUCCESS && id != GUID_NULL)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
// Otherwise keep checking other windows
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ public:
|
||||
std::optional<GUID> GetCurrentVirtualDesktopId() const;
|
||||
std::optional<std::vector<GUID>> GetVirtualDesktopIds() const;
|
||||
|
||||
bool IsWindowOnCurrentDesktop(HWND window) const;
|
||||
std::optional<GUID> GetDesktopId(HWND window) const;
|
||||
|
||||
private:
|
||||
std::function<void()> m_vdInitCallback;
|
||||
std::function<void()> m_vdUpdatedCallback;
|
||||
|
||||
Reference in New Issue
Block a user