[FancyZones] Fix handling newly created windows on Windows 11 (#28646)

This commit is contained in:
Seraphima Zykova
2023-09-21 11:11:51 +03:00
committed by GitHub
parent 59f0ccebc7
commit 8cd2b7cdc3
8 changed files with 91 additions and 88 deletions

View File

@@ -26,6 +26,7 @@
#include <FancyZonesLib/Settings.h>
#include <FancyZonesLib/SettingsObserver.h>
#include <FancyZonesLib/trace.h>
#include <FancyZonesLib/VirtualDesktop.h>
#include <FancyZonesLib/WindowKeyboardSnap.h>
#include <FancyZonesLib/WindowMouseSnap.h>
#include <FancyZonesLib/WorkArea.h>
@@ -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);

View File

@@ -103,6 +103,7 @@
<ClCompile Include="FancyZonesData\LayoutTemplates.cpp">
<PrecompiledHeaderFile>../pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="FancyZonesWindowProcessing.cpp" />
<ClCompile Include="FancyZonesWindowProperties.cpp" />
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
<ClCompile Include="FancyZonesData.cpp" />

View File

@@ -272,6 +272,9 @@
<ClCompile Include="WindowKeyboardSnap.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FancyZonesWindowProcessing.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -0,0 +1,56 @@
#include "pch.h"
#include "FancyZonesWindowProcessing.h"
#include <FancyZonesLib/Settings.h>
#include <FancyZonesLib/VirtualDesktop.h>
#include <FancyZonesLib/WindowUtils.h>
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;
}

View File

@@ -1,39 +1,6 @@
#pragma once
#include <FancyZonesLib/VirtualDesktop.h>
#include <FancyZonesLib/WindowUtils.h>
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;
}

View File

@@ -32,7 +32,6 @@ WindowMouseSnap::~WindowMouseSnap()
std::unique_ptr<WindowMouseSnap> WindowMouseSnap::Create(HWND window, const std::unordered_map<HMONITOR, std::unique_ptr<WorkArea>>& activeWorkAreas)
{
if (!FancyZonesWindowProcessing::IsProcessable(window) ||
!FancyZonesWindowUtils::IsCandidateForZoning(window) ||
FancyZonesWindowUtils::IsCursorTypeIndicatingSizeEvent())
{
return nullptr;

View File

@@ -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<char, 256> class_name;
GetClassNameA(window, class_name.data(), static_cast<int>(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<std::wstring&>(processPath).data(), static_cast<DWORD>(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<std::wstring&>(processPath).data(), static_cast<DWORD>(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<char, 256> class_name;
GetClassNameA(hwnd, class_name.data(), static_cast<int>(class_name.size()));
if (is_system_window(hwnd, class_name.data()))
{
return true;
}
static std::vector<std::wstring> defaultExcludedApps = { NonLocalizable::PowerToysAppFZEditor, NonLocalizable::CoreWindow, NonLocalizable::SearchUI };
return (check_excluded_app(hwnd, processPath, defaultExcludedApps));
}

View File

@@ -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;