diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index d0e1c027f7f..0bf63758157 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -232,7 +232,7 @@ namespace winrt::TerminalApp::implementation void TerminalPage::_HandleToggleFullscreen(const IInspectable& /*sender*/, const TerminalApp::ActionEventArgs& args) { - _ToggleFullscreen(); + ToggleFullscreen(); args.Handled(true); } } diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp index 0d8dbec1a71..62116961957 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.cpp +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.cpp @@ -157,6 +157,7 @@ int AppCommandlineArgs::_handleExit(const CLI::App& command, const CLI::Error& e // - void AppCommandlineArgs::_buildParser() { + // -v,--version: Displays version info auto versionCallback = [this](int64_t /*count*/) { if (const auto appLogic{ winrt::TerminalApp::implementation::AppLogic::Current() }) { @@ -173,6 +174,20 @@ void AppCommandlineArgs::_buildParser() }; _app.add_flag_function("-v,--version", versionCallback, RS_A(L"CmdVersionDesc")); + // Maximized and Fullscreen flags + // -M,--maximized: Maximizes the window on launch + // -F,--fullscreen: Fullscreens the window on launch + auto maximizedCallback = [this](int64_t /*count*/) { + _launchMode = winrt::TerminalApp::LaunchMode::MaximizedMode; + }; + auto fullscreenCallback = [this](int64_t /*count*/) { + _launchMode = winrt::TerminalApp::LaunchMode::FullscreenMode; + }; + auto maximized = _app.add_flag_function("-M,--maximized", maximizedCallback, RS_A(L"CmdMaximizedDesc")); + auto fullscreen = _app.add_flag_function("-F,--fullscreen", fullscreenCallback, RS_A(L"CmdFullscreenDesc")); + maximized->excludes(fullscreen); + + // Subcommands _buildNewTabParser(); _buildSplitPaneParser(); _buildFocusTabParser(); @@ -410,6 +425,10 @@ void AppCommandlineArgs::_resetStateToDefault() _focusTabIndex = -1; _focusNextTab = false; _focusPrevTab = false; + + // DON'T clear _launchMode here! This will get called once for every + // subcommand, so we don't want `wt -F new-tab ; split-pane` clearing out + // the "global" fullscreen flag (-F). } // Function Description: @@ -604,3 +623,8 @@ void AppCommandlineArgs::ValidateStartupCommands() _startupActions.push_front(*newTabAction); } } + +std::optional AppCommandlineArgs::GetLaunchMode() const noexcept +{ + return _launchMode; +} diff --git a/src/cascadia/TerminalApp/AppCommandlineArgs.h b/src/cascadia/TerminalApp/AppCommandlineArgs.h index 1a46d644b8a..268ce55a037 100644 --- a/src/cascadia/TerminalApp/AppCommandlineArgs.h +++ b/src/cascadia/TerminalApp/AppCommandlineArgs.h @@ -38,6 +38,8 @@ class TerminalApp::AppCommandlineArgs final const std::string& GetExitMessage(); bool ShouldExitEarly() const noexcept; + std::optional GetLaunchMode() const noexcept; + private: static const std::wregex _commandDelimiterRegex; @@ -76,6 +78,8 @@ class TerminalApp::AppCommandlineArgs final int _focusTabIndex{ -1 }; bool _focusNextTab{ false }; bool _focusPrevTab{ false }; + + std::optional _launchMode{ std::nullopt }; // Are you adding more args here? Make sure to reset them in _resetStateToDefault std::deque _startupActions; diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index 68c25645019..ada5517833f 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -242,6 +242,17 @@ namespace winrt::TerminalApp::implementation _root->SetSettings(_settings, false); _root->Loaded({ this, &AppLogic::_OnLoaded }); + _root->Initialized([this](auto&&, auto&&) { + // GH#288 - When we finish initialization, if the user wanted us + // launched _fullscreen_, toggle fullscreen mode. This will make sure + // that the window size is _first_ set up as something sensible, so + // leaving fullscreen returns to a reasonable size. + const auto launchMode = this->GetLaunchMode(); + if (launchMode == LaunchMode::FullscreenMode) + { + _root->ToggleFullscreen(); + } + }); _root->Create(); _ApplyTheme(_settings->GlobalSettings().GetTheme()); @@ -529,7 +540,13 @@ namespace winrt::TerminalApp::implementation LoadSettings(); } - return _settings->GlobalSettings().GetLaunchMode(); + // GH#4620/#5801 - If the user passed --maximized or --fullscreen on the + // commandline, then use that to override the value from the settings. + const auto valueFromSettings = _settings->GlobalSettings().GetLaunchMode(); + const auto valueFromCommandlineArgs = _appArgs.GetLaunchMode(); + return valueFromCommandlineArgs.has_value() ? + valueFromCommandlineArgs.value() : + valueFromSettings; } // Method Description: @@ -934,31 +951,108 @@ namespace winrt::TerminalApp::implementation } } - int32_t AppLogic::SetStartupCommandline(array_view actions) + // Method Description: + // - Sets the initial commandline to process on startup, and attempts to + // parse it. Commands will be parsed into a list of ShortcutActions that + // will be processed on TerminalPage::Create(). + // - This function will have no effective result after Create() is called. + // - This function returns 0, unless a there was a non-zero result from + // trying to parse one of the commands provided. In that case, no commands + // after the failing command will be parsed, and the non-zero code + // returned. + // Arguments: + // - args: an array of strings to process as a commandline. These args can contain spaces + // Return Value: + // - the result of the first command who's parsing returned a non-zero code, + // or 0. (see AppLogic::_ParseArgs) + int32_t AppLogic::SetStartupCommandline(array_view args) { - if (_root) + const auto result = _ParseArgs(args); + if (result == 0) { - return _root->SetStartupCommandline(actions); + _appArgs.ValidateStartupCommands(); + _root->SetStartupActions(_appArgs.GetStartupActions()); } - return 0; + + return result; } - winrt::hstring AppLogic::ParseCommandlineMessage() + // Method Description: + // - Attempts to parse an array of commandline args into a list of + // commands to execute, and then parses these commands. As commands are + // successfully parsed, they will generate ShortcutActions for us to be + // able to execute. If we fail to parse any commands, we'll return the + // error code from the failure to parse that command, and stop processing + // additional commands. + // Arguments: + // - args: an array of strings to process as a commandline. These args can contain spaces + // Return Value: + // - 0 if the commandline was successfully parsed + int AppLogic::_ParseArgs(winrt::array_view& args) { - if (_root) + auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args); + + for (auto& cmdBlob : commands) { - return _root->ParseCommandlineMessage(); + // On one hand, it seems like we should be able to have one + // AppCommandlineArgs for parsing all of them, and collect the + // results one at a time. + // + // On the other hand, re-using a CLI::App seems to leave state from + // previous parsings around, so we could get mysterious behavior + // where one command affects the values of the next. + // + // From https://cliutils.github.io/CLI11/book/chapters/options.html: + // > If that option is not given, CLI11 will not touch the initial + // > value. This allows you to set up defaults by simply setting + // > your value beforehand. + // + // So we pretty much need the to either manually reset the state + // each command, or build new ones. + const auto result = _appArgs.ParseCommand(cmdBlob); + + // If this succeeded, result will be 0. Otherwise, the caller should + // exit(result), to exit the program. + if (result != 0) + { + return result; + } } - return { L"" }; + + // If all the args were successfully parsed, we'll have some commands + // built in _appArgs, which we'll use when the application starts up. + return 0; } + // Method Description: + // - If there were any errors parsing the commandline that was used to + // initialize the terminal, this will return a string containing that + // message. If there were no errors, this message will be blank. + // - If the user requested help on any command (using --help), this will + // contain the help message. + // - If the user requested the version number (using --version), this will + // contain the version string. + // Arguments: + // - + // Return Value: + // - the help text or error message for the provided commandline, if one + // exists, otherwise the empty string. + winrt::hstring AppLogic::ParseCommandlineMessage() + { + return winrt::to_hstring(_appArgs.GetExitMessage()); + } + + // Method Description: + // - Returns true if we should exit the application before even starting the + // window. We might want to do this if we're displaying an error message or + // the version string, or if we want to open the settings file. + // Arguments: + // - + // Return Value: + // - true iff we should exit the application before even starting the window bool AppLogic::ShouldExitEarly() { - if (_root) - { - return _root->ShouldExitEarly(); - } - return false; + return _appArgs.ShouldExitEarly(); } winrt::hstring AppLogic::ApplicationDisplayName() const diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index 07e3204d466..c189b1aab38 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -76,6 +76,9 @@ namespace winrt::TerminalApp::implementation std::atomic _settingsReloadQueued{ false }; + ::TerminalApp::AppCommandlineArgs _appArgs; + int _ParseArgs(winrt::array_view& args); + fire_and_forget _ShowDialog(const winrt::Windows::Foundation::IInspectable& sender, winrt::Windows::UI::Xaml::Controls::ContentDialog dialog); void _ShowLoadErrorsDialog(const winrt::hstring& titleKey, const winrt::hstring& contentKey, HRESULT settingsLoadedResult); void _ShowLoadWarningsDialog(); diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index bdc3cf861e8..6afdb0e006c 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -259,6 +259,12 @@ Display the application version + + Launch the window maximized + + + Launch the window in fullscreen mode + Press the button to open a new terminal tab with your default profile. Open the flyout to select which profile you want to open. diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index b45829b7ca5..6e8d850c055 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -184,8 +184,7 @@ namespace winrt::TerminalApp::implementation if (_startupState == StartupState::NotInitialized) { _startupState = StartupState::InStartup; - _appArgs.ValidateStartupCommands(); - if (_appArgs.GetStartupActions().empty()) + if (_startupActions.empty()) { _OpenNewTab(nullptr); @@ -208,7 +207,7 @@ namespace winrt::TerminalApp::implementation winrt::fire_and_forget TerminalPage::_ProcessStartupActions() { // If there are no actions left, do nothing. - if (_appArgs.GetStartupActions().empty()) + if (_startupActions.empty()) { return; } @@ -218,7 +217,7 @@ namespace winrt::TerminalApp::implementation co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal); if (auto page{ weakThis.get() }) { - for (const auto& action : _appArgs.GetStartupActions()) + for (const auto& action : _startupActions) { _actionDispatch->DoAction(action); } @@ -237,14 +236,6 @@ namespace winrt::TerminalApp::implementation // - void TerminalPage::_CompleteInitialization() { - // GH#288 - When we finish initialization, if the user wanted us - // launched _fullscreen_, toggle fullscreen mode. This will make sure - // that the window size is _first_ set up as something sensible, so - // leaving fullscreen returns to a reasonable size. - if (_settings->GlobalSettings().GetLaunchMode() == winrt::TerminalApp::LaunchMode::FullscreenMode) - { - _ToggleFullscreen(); - } _startupState = StartupState::Initialized; _InitializedHandlers(*this, nullptr); } @@ -1776,69 +1767,16 @@ namespace winrt::TerminalApp::implementation } // Method Description: - // - Sets the initial commandline to process on startup, and attempts to - // parse it. Commands will be parsed into a list of ShortcutActions that - // will be processed on TerminalPage::Create(). + // - Sets the initial actions to process on startup. We'll make a copy of + // this list, and process these actions when we're loaded. // - This function will have no effective result after Create() is called. - // - This function returns 0, unless a there was a non-zero result from - // trying to parse one of the commands provided. In that case, no commands - // after the failing command will be parsed, and the non-zero code - // returned. // Arguments: - // - args: an array of strings to process as a commandline. These args can contain spaces + // - actions: a list of Actions to process on startup. // Return Value: - // - the result of the first command who's parsing returned a non-zero code, - // or 0. (see TerminalPage::_ParseArgs) - int32_t TerminalPage::SetStartupCommandline(winrt::array_view args) + // - + void TerminalPage::SetStartupActions(std::deque& actions) { - return _ParseArgs(args); - } - - // Method Description: - // - Attempts to parse an array of commandline args into a list of - // commands to execute, and then parses these commands. As commands are - // successfully parsed, they will generate ShortcutActions for us to be - // able to execute. If we fail to parse any commands, we'll return the - // error code from the failure to parse that command, and stop processing - // additional commands. - // Arguments: - // - args: an array of strings to process as a commandline. These args can contain spaces - // Return Value: - // - 0 if the commandline was successfully parsed - int TerminalPage::_ParseArgs(winrt::array_view& args) - { - auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args); - - for (auto& cmdBlob : commands) - { - // On one hand, it seems like we should be able to have one - // AppCommandlineArgs for parsing all of them, and collect the - // results one at a time. - // - // On the other hand, re-using a CLI::App seems to leave state from - // previous parsings around, so we could get mysterious behavior - // where one command affects the values of the next. - // - // From https://cliutils.github.io/CLI11/book/chapters/options.html: - // > If that option is not given, CLI11 will not touch the initial - // > value. This allows you to set up defaults by simply setting - // > your value beforehand. - // - // So we pretty much need the to either manually reset the state - // each command, or build new ones. - const auto result = _appArgs.ParseCommand(cmdBlob); - - // If this succeeded, result will be 0. Otherwise, the caller should - // exit(result), to exit the program. - if (result != 0) - { - return result; - } - } - - // If all the args were successfully parsed, we'll have some commands - // built in _appArgs, which we'll use when the application starts up. - return 0; + _startupActions = actions; } // Method Description: @@ -1877,7 +1815,7 @@ namespace winrt::TerminalApp::implementation // - // Return Value: // - - void TerminalPage::_ToggleFullscreen() + void TerminalPage::ToggleFullscreen() { _toggleFullscreenHandlers(*this, nullptr); @@ -1886,37 +1824,6 @@ namespace winrt::TerminalApp::implementation _UpdateTabView(); } - // Method Description: - // - If there were any errors parsing the commandline that was used to - // initialize the terminal, this will return a string containing that - // message. If there were no errors, this message will be blank. - // - If the user requested help on any command (using --help), this will - // contain the help message. - // - If the user requested the version number (using --version), this will - // contain the version string. - // Arguments: - // - - // Return Value: - // - the help text or error message for the provided commandline, if one - // exists, otherwise the empty string. - winrt::hstring TerminalPage::ParseCommandlineMessage() - { - return winrt::to_hstring(_appArgs.GetExitMessage()); - } - - // Method Description: - // - Returns true if we should exit the application before even starting the - // window. We might want to do this if we're displaying an error message or - // the version string, or if we want to open the settings file. - // Arguments: - // - - // Return Value: - // - true iff we should exit the application before even starting the window - bool TerminalPage::ShouldExitEarly() - { - return _appArgs.ShouldExitEarly(); - } - // Method Description: // - Returns a com_ptr to the implementation type of the tab at the given index // Arguments: diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index f03a5d639c2..86af8a51069 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -49,9 +49,9 @@ namespace winrt::TerminalApp::implementation void CloseWindow(); - int32_t SetStartupCommandline(winrt::array_view args); - winrt::hstring ParseCommandlineMessage(); - bool ShouldExitEarly(); + void ToggleFullscreen(); + + void SetStartupActions(std::deque& actions); // -------------------------------- WinRT Events --------------------------------- DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(TitleChanged, _titleChangeHandlers, winrt::Windows::Foundation::IInspectable, winrt::hstring); @@ -92,8 +92,7 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::Controls::Grid::LayoutUpdated_revoker _layoutUpdatedRevoker; StartupState _startupState{ StartupState::NotInitialized }; - ::TerminalApp::AppCommandlineArgs _appArgs; - int _ParseArgs(winrt::array_view& args); + std::deque _startupActions; winrt::fire_and_forget _ProcessStartupActions(); void _ShowAboutDialog(); @@ -166,8 +165,6 @@ namespace winrt::TerminalApp::implementation winrt::fire_and_forget _RefreshUIForSettingsReload(); - void _ToggleFullscreen(); - void _SetNonClientAreaColors(const Windows::UI::Color& selectedTabColor); void _ClearNonClientAreaColors(); void _SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor); diff --git a/src/cascadia/TerminalApp/TerminalPage.idl b/src/cascadia/TerminalApp/TerminalPage.idl index ef7ca699de0..d02450fa04e 100644 --- a/src/cascadia/TerminalApp/TerminalPage.idl +++ b/src/cascadia/TerminalApp/TerminalPage.idl @@ -10,10 +10,6 @@ namespace TerminalApp { TerminalPage(); - Int32 SetStartupCommandline(String[] commands); - String ParseCommandlineMessage { get; }; - Boolean ShouldExitEarly { get; }; - // XAML bound properties String ApplicationDisplayName { get; }; String ApplicationVersion { get; };