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