mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
ShortcutGuide, FancyZones: split window filtering (#1225)
Splits the code use to filter windows for FancyZones and the "active window" for the ShortcutGuide. The FancyZones logic is preserved and merged into a single function. We keep it in common.h, as it might be also used in other PowerToys, like maximized to new desktop. We do however change the return type to be more descriptive. It also returns a separate flag for if the window has a visible owner. This can be used to implement the approved apps list. For the ShortcutGuide, the logic is relaxed to include more windows. One example are Explorer properties windows. Those are (and should) filtered by the FancyZones, but should appear in the window preview in the SCG. The new return type also includes information if the window will react to the default Windows Snap. This is not ideal though. Currently, SCG can only disable the entire "Windows Controls" group. OTOH windows like "Save As..." dialogs can be snapped to corners etc., but cannot be minimized nor maximized. Until SCG can separately disable those buttons we will display the buttons in the enabled state only if the window supports all settings. In the future, we should integrate FancyZones snap override here too.
This commit is contained in:
committed by
GitHub
parent
f963d28ba8
commit
0fdc1d0a1f
@@ -53,14 +53,31 @@ static bool is_system_window(HWND hwnd, const char* class_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WindowAndProcPath get_filtered_base_window_and_path(HWND window) {
|
||||
WindowAndProcPath result;
|
||||
auto root = GetAncestor(window, GA_ROOT);
|
||||
if (!IsWindowVisible(root)) {
|
||||
static bool no_visible_owner(HWND window) noexcept
|
||||
{
|
||||
auto owner = GetWindow(window, GW_OWNER);
|
||||
if (owner == nullptr) {
|
||||
return true; // There is no owner at all
|
||||
}
|
||||
if (!IsWindowVisible(owner)) {
|
||||
return true; // Owner is invisible
|
||||
}
|
||||
RECT rect;
|
||||
if (!GetWindowRect(owner, &rect)) {
|
||||
return false; // Could not get the rect, return true (and filter out the window) just in case
|
||||
}
|
||||
// Return false (and allow the window to be zonable) if the owner window size is zero
|
||||
// It is enough that the window is zero-sized in one dimension only.
|
||||
return rect.top == rect.bottom || rect.left == rect.right;
|
||||
}
|
||||
|
||||
FancyZonesFilter get_fancyzones_filtered_window(HWND window) {
|
||||
FancyZonesFilter result;
|
||||
if (GetAncestor(window, GA_ROOT) != window || !IsWindowVisible(window)) {
|
||||
return result;
|
||||
}
|
||||
auto style = GetWindowLong(root, GWL_STYLE);
|
||||
auto exStyle = GetWindowLong(root, GWL_EXSTYLE);
|
||||
auto style = GetWindowLong(window, GWL_STYLE);
|
||||
auto exStyle = GetWindowLong(window, GWL_EXSTYLE);
|
||||
// WS_POPUP need to have a border or minimize/maximize buttons,
|
||||
// otherwise the window is "not interesting"
|
||||
if ((style & WS_POPUP) == WS_POPUP &&
|
||||
@@ -76,23 +93,66 @@ WindowAndProcPath get_filtered_base_window_and_path(HWND window) {
|
||||
return result;
|
||||
}
|
||||
std::array<char, 256> class_name;
|
||||
GetClassNameA(root, class_name.data(), static_cast<int>(class_name.size()));
|
||||
if (is_system_window(root, class_name.data())) {
|
||||
GetClassNameA(window, class_name.data(), static_cast<int>(class_name.size()));
|
||||
if (is_system_window(window, class_name.data())) {
|
||||
return result;
|
||||
}
|
||||
auto process_path = get_process_path(root);
|
||||
auto process_path = get_process_path(window);
|
||||
// Check for Cortana:
|
||||
if (strcmp(class_name.data(), "Windows.UI.Core.CoreWindow") == 0 &&
|
||||
process_path.ends_with(L"SearchUI.exe")) {
|
||||
return result;
|
||||
}
|
||||
result.hwnd = root;
|
||||
result.process_path = std::move(process_path);
|
||||
result.standard_window = true;
|
||||
result.no_visible_owner = no_visible_owner(window);
|
||||
result.zonable = result.standard_window && result.no_visible_owner;
|
||||
return result;
|
||||
}
|
||||
|
||||
HWND get_filtered_active_window() {
|
||||
return get_filtered_base_window_and_path(GetForegroundWindow()).hwnd;
|
||||
ShortcutGuideFilter get_shortcutguide_filtered_window() {
|
||||
ShortcutGuideFilter result;
|
||||
auto active_window = GetForegroundWindow();
|
||||
active_window = GetAncestor(active_window, GA_ROOT);
|
||||
if (!IsWindowVisible(active_window)) {
|
||||
return result;
|
||||
}
|
||||
auto style = GetWindowLong(active_window, GWL_STYLE);
|
||||
auto exStyle = GetWindowLong(active_window, GWL_EXSTYLE);
|
||||
if ((style & WS_CHILD) == WS_CHILD ||
|
||||
(style & WS_DISABLED) == WS_DISABLED ||
|
||||
(exStyle & WS_EX_TOOLWINDOW) == WS_EX_TOOLWINDOW ||
|
||||
(exStyle & WS_EX_NOACTIVATE) == WS_EX_NOACTIVATE) {
|
||||
return result;
|
||||
}
|
||||
std::array<char, 256> class_name;
|
||||
GetClassNameA(active_window, class_name.data(), static_cast<int>(class_name.size()));
|
||||
if (is_system_window(active_window, class_name.data())) {
|
||||
return result;
|
||||
}
|
||||
static HWND cortanda_hwnd = nullptr;
|
||||
if (cortanda_hwnd == nullptr) {
|
||||
if (strcmp(class_name.data(), "Windows.UI.Core.CoreWindow") == 0 &&
|
||||
get_process_path(active_window).ends_with(L"SearchUI.exe")) {
|
||||
cortanda_hwnd = active_window;
|
||||
return result;
|
||||
}
|
||||
} else if (cortanda_hwnd == active_window) {
|
||||
return result;
|
||||
}
|
||||
result.hwnd = active_window;
|
||||
// In reality, Windows Snap works if even one of those styles is set
|
||||
// for a window, it is just limited. If there is no WS_MAXIMIZEBOX using
|
||||
// WinKey + Up just won't maximize the window. Similary, without
|
||||
// WS_MINIMIZEBOX the window will not get minimized. A "Save As..." dialog
|
||||
// is a example of such window - it can be snapped to both sides and to
|
||||
// all screen conrers, but will not get maximized nor minimized.
|
||||
// For now, since ShortcutGuide can only disable entire "Windows Controls"
|
||||
// group, we require that the window supports all the options.
|
||||
result.snappable = ((style & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX) &&
|
||||
((style & WS_MINIMIZEBOX) == WS_MINIMIZEBOX) &&
|
||||
((style & WS_THICKFRAME) == WS_THICKFRAME);
|
||||
return result;
|
||||
}
|
||||
|
||||
int width(const RECT& rect) {
|
||||
|
||||
Reference in New Issue
Block a user