Add support for --fullscreen, --maximized (#6139)

## Summary of the Pull Request

Adds two new flags to the `wt.exe` alias:

* `--maximized,-M`: Launch the new Terminal window maximized. This flag cannot be combined with `--fullscreen`.
* `--fullscreen,-F`: Launch the new Terminal window fullscreen. This flag cannot be combined with `--maximized`.

## References
* This builds on the work done in #6060.
* The cmdline args megathread: #4632

## PR Checklist
* [x] Closes #5801
* [x] I work here
* [ ] Tests added/passed
* [n/a] Requires documentation to be updated

## Detailed Description of the Pull Request / Additional comments

* I had to move the commandline arg parsing up a layer from `TerminalPage` to `AppLogic`, because `AppLogic` controls the Terminal's settings, including launch mode settings. This seems like a reasonable change, to put both the settings from the file and the commandline in the same place.
  - **Most of the diff is that movement of code**

* _"What happens when you try to pass both flags, like `wtd -M -F new-tab`?"_:
![image](https://user-images.githubusercontent.com/18356694/82679939-3cffde00-9c11-11ea-8d88-03ec7db83e59.png)

## Validation Steps Performed
* Ran a bunch of commandlines to see what happened.
This commit is contained in:
Mike Griese 2020-06-01 16:57:30 -05:00 committed by GitHub
parent d92c8293ce
commit 8987486e85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 160 additions and 129 deletions

View File

@ -232,7 +232,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleToggleFullscreen(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{
_ToggleFullscreen();
ToggleFullscreen();
args.Handled(true);
}
}

View File

@ -157,6 +157,7 @@ int AppCommandlineArgs::_handleExit(const CLI::App& command, const CLI::Error& e
// - <none>
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<winrt::TerminalApp::LaunchMode> AppCommandlineArgs::GetLaunchMode() const noexcept
{
return _launchMode;
}

View File

@ -38,6 +38,8 @@ public:
const std::string& GetExitMessage();
bool ShouldExitEarly() const noexcept;
std::optional<winrt::TerminalApp::LaunchMode> GetLaunchMode() const noexcept;
private:
static const std::wregex _commandDelimiterRegex;
@ -76,6 +78,8 @@ private:
int _focusTabIndex{ -1 };
bool _focusNextTab{ false };
bool _focusPrevTab{ false };
std::optional<winrt::TerminalApp::LaunchMode> _launchMode{ std::nullopt };
// Are you adding more args here? Make sure to reset them in _resetStateToDefault
std::deque<winrt::TerminalApp::ActionAndArgs> _startupActions;

View File

@ -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<const winrt::hstring> 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<const winrt::hstring> args)
{
if (_root)
const auto result = _ParseArgs(args);
if (result == 0)
{
return _root->SetStartupCommandline(actions);
_appArgs.ValidateStartupCommands();
_root->SetStartupActions(_appArgs.GetStartupActions());
}
return result;
}
// 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<const hstring>& 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;
}
// 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:
// - <none>
// Return Value:
// - the help text or error message for the provided commandline, if one
// exists, otherwise the empty string.
winrt::hstring AppLogic::ParseCommandlineMessage()
{
if (_root)
{
return _root->ParseCommandlineMessage();
}
return { L"" };
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:
// - <none>
// 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

View File

@ -76,6 +76,9 @@ namespace winrt::TerminalApp::implementation
std::atomic<bool> _settingsReloadQueued{ false };
::TerminalApp::AppCommandlineArgs _appArgs;
int _ParseArgs(winrt::array_view<const hstring>& 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();

View File

@ -259,6 +259,12 @@
<data name="CmdVersionDesc" xml:space="preserve">
<value>Display the application version</value>
</data>
<data name="CmdMaximizedDesc" xml:space="preserve">
<value>Launch the window maximized</value>
</data>
<data name="CmdFullscreenDesc" xml:space="preserve">
<value>Launch the window in fullscreen mode</value>
</data>
<data name="NewTabSplitButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.HelpText" xml:space="preserve">
<value>Press the button to open a new terminal tab with your default profile. Open the flyout to select which profile you want to open.</value>
</data>

View File

@ -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
// - <none>
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<const hstring> args)
// - <none>
void TerminalPage::SetStartupActions(std::deque<winrt::TerminalApp::ActionAndArgs>& 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<const hstring>& 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
// - <none>
// Return Value:
// - <none>
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:
// - <none>
// 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:
// - <none>
// 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:

View File

@ -49,9 +49,9 @@ namespace winrt::TerminalApp::implementation
void CloseWindow();
int32_t SetStartupCommandline(winrt::array_view<const hstring> args);
winrt::hstring ParseCommandlineMessage();
bool ShouldExitEarly();
void ToggleFullscreen();
void SetStartupActions(std::deque<winrt::TerminalApp::ActionAndArgs>& 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<const hstring>& args);
std::deque<winrt::TerminalApp::ActionAndArgs> _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);

View File

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