From 8cd2b7cdc3fa0eeb4ae7ed175aa2d418aefb3fd5 Mon Sep 17 00:00:00 2001 From: Seraphima Zykova Date: Thu, 21 Sep 2023 11:11:51 +0300 Subject: [PATCH] [FancyZones] Fix handling newly created windows on Windows 11 (#28646) --- .../fancyzones/FancyZonesLib/FancyZones.cpp | 9 +-- .../FancyZonesLib/FancyZonesLib.vcxproj | 1 + .../FancyZonesLib.vcxproj.filters | 3 + .../FancyZonesWindowProcessing.cpp | 56 +++++++++++++++ .../FancyZonesWindowProcessing.h | 35 +-------- .../FancyZonesLib/WindowMouseSnap.cpp | 1 - .../fancyzones/FancyZonesLib/WindowUtils.cpp | 71 +++++++------------ .../fancyzones/FancyZonesLib/WindowUtils.h | 3 +- 8 files changed, 91 insertions(+), 88 deletions(-) create mode 100644 src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProcessing.cpp diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp index 76f99175d5..7ddcd955c5 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp +++ b/src/modules/fancyzones/FancyZonesLib/FancyZones.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -397,12 +398,6 @@ void FancyZones::WindowCreated(HWND window) noexcept return; } - const bool isCandidateForLastKnownZone = FancyZonesWindowUtils::IsCandidateForZoning(window); - if (!isCandidateForLastKnownZone) - { - return; - } - HMONITOR primary = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY); HMONITOR active = primary; @@ -994,7 +989,7 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept return false; } - if (FancyZonesSettings::settings().overrideSnapHotkeys && FancyZonesWindowUtils::IsCandidateForZoning(window)) + if (FancyZonesSettings::settings().overrideSnapHotkeys) { HMONITOR monitor = WorkAreaKeyFromWindow(window); diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj index 9bb26ccd95..a659a1839e 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj @@ -103,6 +103,7 @@ ../pch.h + diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters index e8012868f2..f97b95c5a9 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesLib.vcxproj.filters @@ -272,6 +272,9 @@ Source Files + + Source Files + diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProcessing.cpp b/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProcessing.cpp new file mode 100644 index 0000000000..102392ba91 --- /dev/null +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProcessing.cpp @@ -0,0 +1,56 @@ +#include "pch.h" +#include "FancyZonesWindowProcessing.h" + +#include +#include +#include + +bool FancyZonesWindowProcessing::IsProcessable(HWND window) noexcept +{ + const bool isSplashScreen = FancyZonesWindowUtils::IsSplashScreen(window); + if (isSplashScreen) + { + return false; + } + + const bool windowMinimized = IsIconic(window); + if (windowMinimized) + { + return false; + } + + const bool standard = FancyZonesWindowUtils::IsStandardWindow(window); + if (!standard) + { + return false; + } + + // popup could be the window we don't want to snap: start menu, notification popup, tray window, etc. + // also, popup could be the windows we want to snap disregarding the "allowSnapPopupWindows" setting, e.g. Telegram + bool isPopup = FancyZonesWindowUtils::IsPopupWindow(window) && !FancyZonesWindowUtils::HasThickFrameAndMinimizeMaximizeButtons(window); + if (isPopup && !FancyZonesSettings::settings().allowSnapPopupWindows) + { + return false; + } + + // allow child windows + auto hasOwner = FancyZonesWindowUtils::HasVisibleOwner(window); + if (hasOwner && !FancyZonesSettings::settings().allowSnapChildWindows) + { + return false; + } + + if (FancyZonesWindowUtils::IsExcluded(window)) + { + return false; + } + + // 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. + if (!VirtualDesktop::instance().IsWindowOnCurrentDesktop(window)) + { + return false; + } + + return true; +} diff --git a/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProcessing.h b/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProcessing.h index fc2108ffbb..21fbcfbad2 100644 --- a/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProcessing.h +++ b/src/modules/fancyzones/FancyZonesLib/FancyZonesWindowProcessing.h @@ -1,39 +1,6 @@ #pragma once -#include -#include - namespace FancyZonesWindowProcessing { - inline bool IsProcessable(HWND window) noexcept - { - const bool isSplashScreen = FancyZonesWindowUtils::IsSplashScreen(window); - if (isSplashScreen) - { - return false; - } - - const bool windowMinimized = IsIconic(window); - if (windowMinimized) - { - return false; - } - - // For windows that FancyZones shouldn't process (start menu, tray, popup menus) - // VirtualDesktopManager is unable to retrieve virtual desktop id and returns an error. - auto desktopId = VirtualDesktop::instance().GetDesktopId(window); - if (!desktopId.has_value()) - { - return false; - } - - // 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. - if (!VirtualDesktop::instance().IsWindowOnCurrentDesktop(window)) - { - return false; - } - - return true; - } + bool IsProcessable(HWND window) noexcept; } \ No newline at end of file diff --git a/src/modules/fancyzones/FancyZonesLib/WindowMouseSnap.cpp b/src/modules/fancyzones/FancyZonesLib/WindowMouseSnap.cpp index c6b8f8cedd..a69aaa7ef7 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowMouseSnap.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WindowMouseSnap.cpp @@ -32,7 +32,6 @@ WindowMouseSnap::~WindowMouseSnap() std::unique_ptr WindowMouseSnap::Create(HWND window, const std::unordered_map>& activeWorkAreas) { if (!FancyZonesWindowProcessing::IsProcessable(window) || - !FancyZonesWindowUtils::IsCandidateForZoning(window) || FancyZonesWindowUtils::IsCursorTypeIndicatingSizeEvent()) { return nullptr; diff --git a/src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp b/src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp index dbad77732c..ef895cf830 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp @@ -166,6 +166,8 @@ bool FancyZonesWindowUtils::HasVisibleOwner(HWND window) noexcept bool FancyZonesWindowUtils::IsStandardWindow(HWND window) { + // True if from the styles the window looks like a standard window + if (GetAncestor(window, GA_ROOT) != window) { return false; @@ -181,13 +183,6 @@ bool FancyZonesWindowUtils::IsStandardWindow(HWND window) return false; } - std::array class_name; - GetClassNameA(window, class_name.data(), static_cast(class_name.size())); - if (is_system_window(window, class_name.data())) - { - return false; - } - return true; } @@ -203,44 +198,6 @@ bool FancyZonesWindowUtils::HasThickFrameAndMinimizeMaximizeButtons(HWND window) return ((style & WS_THICKFRAME) == WS_THICKFRAME && (style & WS_MINIMIZEBOX) == WS_MINIMIZEBOX && (style & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX); } -bool FancyZonesWindowUtils::IsCandidateForZoning(HWND window) -{ - bool isStandard = IsStandardWindow(window); - if (!isStandard) - { - return false; - } - - // popup could be the window we don't want to snap: start menu, notification popup, tray window, etc. - // also, popup could be the windows we want to snap disregarding the "allowSnapPopupWindows" setting, e.g. Telegram - bool isPopup = IsPopupWindow(window); - if (isPopup && !HasThickFrameAndMinimizeMaximizeButtons(window) && !FancyZonesSettings::settings().allowSnapPopupWindows) - { - return false; - } - - // allow child windows - auto hasOwner = HasVisibleOwner(window); - if (hasOwner && !FancyZonesSettings::settings().allowSnapChildWindows) - { - return false; - } - - std::wstring processPath = get_process_path_waiting_uwp(window); - CharUpperBuffW(const_cast(processPath).data(), static_cast(processPath.length())); - if (IsExcludedByUser(window, processPath)) - { - return false; - } - - if (IsExcludedByDefault(window, processPath)) - { - return false; - } - - return true; -} - bool FancyZonesWindowUtils::IsProcessOfWindowElevated(HWND window) { DWORD pid = 0; @@ -268,6 +225,23 @@ bool FancyZonesWindowUtils::IsProcessOfWindowElevated(HWND window) return false; } +bool FancyZonesWindowUtils::IsExcluded(HWND window) +{ + std::wstring processPath = get_process_path_waiting_uwp(window); + CharUpperBuffW(const_cast(processPath).data(), static_cast(processPath.length())); + if (IsExcludedByUser(window, processPath)) + { + return true; + } + + if (IsExcludedByDefault(window, processPath)) + { + return true; + } + + return false; +} + bool FancyZonesWindowUtils::IsExcludedByUser(const HWND& hwnd, std::wstring& processPath) noexcept { return (check_excluded_app(hwnd, processPath, FancyZonesSettings::settings().excludedAppsArray)); @@ -281,6 +255,13 @@ bool FancyZonesWindowUtils::IsExcludedByDefault(const HWND& hwnd, std::wstring& return true; } + std::array class_name; + GetClassNameA(hwnd, class_name.data(), static_cast(class_name.size())); + if (is_system_window(hwnd, class_name.data())) + { + return true; + } + static std::vector defaultExcludedApps = { NonLocalizable::PowerToysAppFZEditor, NonLocalizable::CoreWindow, NonLocalizable::SearchUI }; return (check_excluded_app(hwnd, processPath, defaultExcludedApps)); } diff --git a/src/modules/fancyzones/FancyZonesLib/WindowUtils.h b/src/modules/fancyzones/FancyZonesLib/WindowUtils.h index 9659d78b9c..4ac973bacb 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowUtils.h +++ b/src/modules/fancyzones/FancyZonesLib/WindowUtils.h @@ -21,8 +21,9 @@ namespace FancyZonesWindowUtils bool IsStandardWindow(HWND window); bool IsPopupWindow(HWND window) noexcept; bool HasThickFrameAndMinimizeMaximizeButtons(HWND window) noexcept; - bool IsCandidateForZoning(HWND window); bool IsProcessOfWindowElevated(HWND window); // If HWND is already dead, we assume it wasn't elevated + + bool IsExcluded(HWND window); bool IsExcludedByUser(const HWND& hwnd, std::wstring& processPath) noexcept; bool IsExcludedByDefault(const HWND& hwnd, std::wstring& processPath) noexcept;