diff --git a/src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp b/src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp index 62084e1c8d30..f8b54bf184ed 100644 --- a/src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp +++ b/src/modules/fancyzones/FancyZonesLib/MonitorUtils.cpp @@ -340,8 +340,9 @@ namespace MonitorUtils { // By default Windows opens new window on primary monitor. // Try to preserve window width and height, adjust top-left corner if needed. + // Continue if current window is always maximize by user setting HMONITOR origin = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); - if (origin == monitor) + if (!FancyZonesWindowUtils::IsAlwaysMaximize(window) && origin == monitor) { // Certain applications by design open in last known position, regardless of FancyZones. // If that position is on currently active monitor, skip custom positioning. diff --git a/src/modules/fancyzones/FancyZonesLib/Settings.cpp b/src/modules/fancyzones/FancyZonesLib/Settings.cpp index 865c1c18931c..ebd8cd8a0e24 100644 --- a/src/modules/fancyzones/FancyZonesLib/Settings.cpp +++ b/src/modules/fancyzones/FancyZonesLib/Settings.cpp @@ -46,6 +46,7 @@ namespace NonLocalizable const wchar_t WindowSwitchingToggleID[] = L"fancyzones_windowSwitching"; const wchar_t NextTabHotkeyID[] = L"fancyzones_nextTab_hotkey"; const wchar_t PrevTabHotkeyID[] = L"fancyzones_prevTab_hotkey"; + const wchar_t AlwaysMaximizeID[] = L"fancyzones_always_maximize"; const wchar_t ExcludedAppsID[] = L"fancyzones_excluded_apps"; const wchar_t ZoneHighlightOpacityID[] = L"fancyzones_highlight_opacity"; const wchar_t ShowZoneNumberID[] = L"fancyzones_showZoneNumber"; @@ -208,6 +209,32 @@ void FancyZonesSettings::LoadSettings() } } + // always maximize apps + if (auto val = values.get_string_value(NonLocalizable::AlwaysMaximizeID)) + { + std::wstring apps = std::move(*val); + std::vector alwaysMaximize; + auto alwaysMaximizeUppercase = apps; + CharUpperBuffW(alwaysMaximizeUppercase.data(), static_cast(alwaysMaximizeUppercase.length())); + std::wstring_view view(alwaysMaximizeUppercase); + view = left_trim(trim(view)); + + while (!view.empty()) + { + auto pos = (std::min)(view.find_first_of(L"\r\n"), view.length()); + alwaysMaximize.emplace_back(view.substr(0, pos)); + view.remove_prefix(pos); + view = left_trim(trim(view)); + } + + if (m_settings.alwaysMaximizeArray != alwaysMaximize) + { + m_settings.alwaysMaximize = apps; + m_settings.alwaysMaximizeArray = alwaysMaximize; + NotifyObservers(SettingId::AlwaysMaximize); + } + } + // excluded apps if (auto val = values.get_string_value(NonLocalizable::ExcludedAppsID)) { diff --git a/src/modules/fancyzones/FancyZonesLib/Settings.h b/src/modules/fancyzones/FancyZonesLib/Settings.h index 632c6a3a780d..f76ab8ae8863 100644 --- a/src/modules/fancyzones/FancyZonesLib/Settings.h +++ b/src/modules/fancyzones/FancyZonesLib/Settings.h @@ -57,6 +57,8 @@ struct Settings bool windowSwitching = true; PowerToysSettings::HotkeyObject nextTabHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, false, VK_NEXT); PowerToysSettings::HotkeyObject prevTabHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, false, VK_PRIOR); + std::wstring alwaysMaximize = L""; + std::vector alwaysMaximizeArray; std::wstring excludedApps = L""; std::vector excludedAppsArray; }; diff --git a/src/modules/fancyzones/FancyZonesLib/SettingsConstants.h b/src/modules/fancyzones/FancyZonesLib/SettingsConstants.h index 1797d60116d0..dd15ef549f1a 100644 --- a/src/modules/fancyzones/FancyZonesLib/SettingsConstants.h +++ b/src/modules/fancyzones/FancyZonesLib/SettingsConstants.h @@ -31,6 +31,7 @@ enum class SettingId WindowSwitching, NextTabHotkey, PrevTabHotkey, + AlwaysMaximize, ExcludedApps, AllowSnapPopupWindows, AllowSnapChildWindows, diff --git a/src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp b/src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp index e84d3e822f3d..ee731f5caf2a 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp +++ b/src/modules/fancyzones/FancyZonesLib/WindowUtils.cpp @@ -225,6 +225,18 @@ bool FancyZonesWindowUtils::IsProcessOfWindowElevated(HWND window) return false; } +bool FancyZonesWindowUtils::IsAlwaysMaximize(HWND window) +{ + std::wstring processPath = get_process_path_waiting_uwp(window); + CharUpperBuffW(const_cast(processPath).data(), static_cast(processPath.length())); + if (find_app_name_in_path(processPath, FancyZonesSettings::settings().alwaysMaximizeArray)) + { + return true; + } + + return false; +} + bool FancyZonesWindowUtils::IsExcluded(HWND window) { std::wstring processPath = get_process_path_waiting_uwp(window); @@ -308,9 +320,16 @@ void FancyZonesWindowUtils::SizeWindowToRect(HWND window, RECT rect, BOOL snapZo else { // If is not snap zone then need keep maximize state (move to active monitor) - if (!snapZone && placement.showCmd == SW_SHOWMAXIMIZED) + if (!snapZone) { - maximizeLater = true; + if (IsAlwaysMaximize(window)) + { + placement.showCmd = SW_SHOWMAXIMIZED; + } + if (placement.showCmd == SW_SHOWMAXIMIZED) + { + maximizeLater = true; + } } // Do not restore minimized windows. We change their placement though so they restore to the correct zone. diff --git a/src/modules/fancyzones/FancyZonesLib/WindowUtils.h b/src/modules/fancyzones/FancyZonesLib/WindowUtils.h index 98e093355e4e..7bf0fccf73e5 100644 --- a/src/modules/fancyzones/FancyZonesLib/WindowUtils.h +++ b/src/modules/fancyzones/FancyZonesLib/WindowUtils.h @@ -23,6 +23,7 @@ namespace FancyZonesWindowUtils bool HasThickFrameAndMinimizeMaximizeButtons(HWND window) noexcept; bool IsProcessOfWindowElevated(HWND window); // If HWND is already dead, we assume it wasn't elevated + bool IsAlwaysMaximize(HWND window); bool IsExcluded(HWND window); bool IsExcludedByUser(const HWND& hwnd, std::wstring& processPath) noexcept; bool IsExcludedByDefault(const HWND& hwnd, std::wstring& processPath) noexcept; diff --git a/src/modules/fancyzones/FancyZonesLib/trace.cpp b/src/modules/fancyzones/FancyZonesLib/trace.cpp index 0fce61584fed..4468d4a294f5 100644 --- a/src/modules/fancyzones/FancyZonesLib/trace.cpp +++ b/src/modules/fancyzones/FancyZonesLib/trace.cpp @@ -67,6 +67,7 @@ #define WindowSwitchingToggleKey "WindowSwitchingToggle" #define NextTabHotkey "NextTabHotkey" #define PrevTabHotkey "PrevTabHotkey" +#define AlwaysMaximizeCountKey "AlwaysMaximizeCount" #define ExcludedAppsCountKey "ExcludedAppsCount" #define KeyboardValueKey "KeyboardValue" #define ActiveSetKey "ActiveSet" @@ -334,6 +335,7 @@ void Trace::SettingsTelemetry(const Settings& settings) noexcept TraceLoggingBoolean(settings.windowSwitching, WindowSwitchingToggleKey), TraceLoggingWideString(nextTabHotkeyStr.c_str(), NextTabHotkey), TraceLoggingWideString(prevTabHotkeyStr.c_str(), PrevTabHotkey), + TraceLoggingInt32(static_cast(settings.excludedAppsArray.size()), AlwaysMaximizeCountKey), TraceLoggingInt32(static_cast(settings.excludedAppsArray.size()), ExcludedAppsCountKey)); } diff --git a/src/settings-ui/Settings.UI.Library/FZConfigProperties.cs b/src/settings-ui/Settings.UI.Library/FZConfigProperties.cs index f64ee5fc1293..d956d8c8a86e 100644 --- a/src/settings-ui/Settings.UI.Library/FZConfigProperties.cs +++ b/src/settings-ui/Settings.UI.Library/FZConfigProperties.cs @@ -47,6 +47,7 @@ public FZConfigProperties() FancyzonesAllowPopupWindowSnap = new BoolProperty(); FancyzonesAllowChildWindowSnap = new BoolProperty(); FancyzonesDisableRoundCornersOnSnap = new BoolProperty(); + FancyzonesALwaysMaximize = new StringProperty(); FancyzonesExcludedApps = new StringProperty(); FancyzonesInActiveColor = new StringProperty(ConfigDefaults.DefaultFancyZonesInActiveColor); FancyzonesBorderColor = new StringProperty(ConfigDefaults.DefaultFancyzonesBorderColor); @@ -136,6 +137,9 @@ public FZConfigProperties() [JsonPropertyName("fancyzones_prevTab_hotkey")] public KeyboardKeysProperty FancyzonesPrevTabHotkey { get; set; } + [JsonPropertyName("fancyzones_always_maximize")] + public StringProperty FancyzonesALwaysMaximize { get; set; } + [JsonPropertyName("fancyzones_excluded_apps")] public StringProperty FancyzonesExcludedApps { get; set; } diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/FancyZonesPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/FancyZonesPage.xaml index de957df76cfa..3ade45ab5208 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/FancyZonesPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/FancyZonesPage.xaml @@ -214,6 +214,25 @@ + + + + + + + + diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index 50dfcccfb65f..0f74563c6bc9 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -861,6 +861,16 @@ Excludes an application from snapping to zones and will only react to Windows Snap - add one application name per line + + Always maximize apps + + + Always create new window application with maximize state - add one application name per line + + + Example: outlook.exe + Don't translate outlook.exe + Opacity (%) diff --git a/src/settings-ui/Settings.UI/ViewModels/FancyZonesViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/FancyZonesViewModel.cs index 358fbc97a43d..c8861da1f374 100644 --- a/src/settings-ui/Settings.UI/ViewModels/FancyZonesViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/FancyZonesViewModel.cs @@ -94,6 +94,7 @@ public FancyZonesViewModel(SettingsUtils settingsUtils, ISettingsRepository