diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index 94010170f6..4d188bd5c2 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -157,8 +157,9 @@ private: void OnSettingsChanged() noexcept; - std::pair, ZoneIndexSet> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept; + std::pair, ZoneIndexSet> GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map>& workAreaMap) noexcept; void MoveWindowIntoZone(HWND window, winrt::com_ptr 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, ZoneIndexSet> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, bool isPrimaryMonitor) noexcept +std::pair, ZoneIndexSet> FancyZones::GetAppZoneHistoryInfo(HWND window, HMONITOR monitor, const std::unordered_map>& workAreaMap) noexcept { - std::pair, 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, 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, ZoneIndexSet>{ workArea, zoneIndexSet }; } } } - - return appZoneHistoryInfo; + + return std::pair, ZoneIndexSet>{ nullptr, {} }; } void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr zoneWindow, const ZoneIndexSet& zoneIndexSet) noexcept @@ -313,62 +307,108 @@ void FancyZones::MoveWindowIntoZone(HWND window, winrt::com_ptr 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, 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(::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, 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(::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(); } } diff --git a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp index 409face59f..cbce8c78e8 100644 --- a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp +++ b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.cpp @@ -210,6 +210,28 @@ std::optional> VirtualDesktop::GetVirtualDesktopIds() const return GetVirtualDesktopIds(GetVirtualDesktopsRegKey()); } +bool VirtualDesktop::IsWindowOnCurrentDesktop(HWND window) const +{ + std::optional id = GetDesktopId(window); + return id.has_value(); +} + +std::optional 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 VirtualDesktop::GetDesktopIdByTopLevelWindows() const { using result_t = std::vector; @@ -222,16 +244,13 @@ std::optional VirtualDesktop::GetDesktopIdByTopLevelWindows() const }; EnumWindows(callback, reinterpret_cast(&result)); - GUID id; - BOOL isWindowOnCurrentDesktop = false; for (const auto window : result) { - if (m_vdManager->IsWindowOnCurrentVirtualDesktop(window, &isWindowOnCurrentDesktop) == ERROR_SUCCESS && isWindowOnCurrentDesktop) + std::optional 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; } } diff --git a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h index db65baf204..d634cc95a2 100644 --- a/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h +++ b/src/modules/fancyzones/FancyZonesLib/VirtualDesktop.h @@ -16,6 +16,9 @@ public: std::optional GetCurrentVirtualDesktopId() const; std::optional> GetVirtualDesktopIds() const; + bool IsWindowOnCurrentDesktop(HWND window) const; + std::optional GetDesktopId(HWND window) const; + private: std::function m_vdInitCallback; std::function m_vdUpdatedCallback;