Enable Terminal closing with ALT + F4 and warning of multiple open tabs (#2526)
* ALT+F4 to close the terminal app window and warn user of multiple tabs * Fix indent issue * Indentation issue fix 2 * add some comments * move close window warning texts to resources * CR feedback changes - 8/28 * fix resource file space issue * Fix resource file space issue 2 * Fix resource file space issue * minor CR changes * update comments * Sync to the latest master branch * CR changes round 2 * Format fix * fix type conversion warning * CR changes on 9-12 * CR feedback changes on 9-12 * add comments why we remove tabs in reverse order * Fix warnings
This commit is contained in:
parent
2d0608d8c0
commit
5806cdab52
|
@ -167,9 +167,12 @@ namespace winrt::TerminalApp::implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Show a ContentDialog with a single button to dismiss. Uses the
|
// - Show a ContentDialog with buttons to take further action. Uses the
|
||||||
// FrameworkElements provided as the title and content of this dialog, and
|
// FrameworkElements provided as the title and content of this dialog, and
|
||||||
// displays a single button to dismiss.
|
// displays buttons (or a single button). Two buttons (primary and secondary)
|
||||||
|
// will be displayed if this is an warning dialog for closing the termimal,
|
||||||
|
// this allows the users to abondon the closing action. Otherwise, a single
|
||||||
|
// close button will be displayed.
|
||||||
// - Only one dialog can be visible at a time. If another dialog is visible
|
// - Only one dialog can be visible at a time. If another dialog is visible
|
||||||
// when this is called, nothing happens.
|
// when this is called, nothing happens.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
|
|
@ -60,6 +60,13 @@ namespace winrt::TerminalApp::implementation
|
||||||
args.Handled(true);
|
args.Handled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/,
|
||||||
|
const TerminalApp::ActionEventArgs& args)
|
||||||
|
{
|
||||||
|
_CloseWindow();
|
||||||
|
args.Handled(true);
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalPage::_HandleScrollUp(const IInspectable& /*sender*/,
|
void TerminalPage::_HandleScrollUp(const IInspectable& /*sender*/,
|
||||||
const TerminalApp::ActionEventArgs& args)
|
const TerminalApp::ActionEventArgs& args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
|
|
||||||
Version 2.0
|
Version 2.0
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
The primary goals of this format is to allow a simple XML format
|
||||||
that is mostly human readable. The generation and parsing of the
|
that is mostly human readable. The generation and parsing of the
|
||||||
various data types are done through the TypeConverter classes
|
various data types are done through the TypeConverter classes
|
||||||
associated with the data types.
|
associated with the data types.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
... ado.net/XML headers & schema ...
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
<resheader name="version">2.0</resheader>
|
<resheader name="version">2.0</resheader>
|
||||||
|
@ -26,36 +26,36 @@
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
<comment>This is a comment</comment>
|
<comment>This is a comment</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
There are any number of "resheader" rows that contain simple
|
||||||
name/value pairs.
|
name/value pairs.
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
Each data row contains a name, and value. The row also contains a
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
text/value conversion through the TypeConverter architecture.
|
text/value conversion through the TypeConverter architecture.
|
||||||
Classes that don't support this are serialized and stored with the
|
Classes that don't support this are serialized and stored with the
|
||||||
mimetype set.
|
mimetype set.
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
The mimetype is used for serialized objects, and tells the
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
read any of the formats listed below.
|
read any of the formats listed below.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
value : The object must be serialized into a byte array
|
value : The object must be serialized into a byte array
|
||||||
: using a System.ComponentModel.TypeConverter
|
: using a System.ComponentModel.TypeConverter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
-->
|
-->
|
||||||
|
@ -193,4 +193,13 @@ Temporarily using the Windows Terminal default settings.
|
||||||
<data name="SettingsMenuItem" xml:space="preserve">
|
<data name="SettingsMenuItem" xml:space="preserve">
|
||||||
<value>Settings</value>
|
<value>Settings</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="Cancel" xml:space="preserve">
|
||||||
|
<value>Cancel</value>
|
||||||
|
</data>
|
||||||
|
<data name="CloseAll" xml:space="preserve">
|
||||||
|
<value>Close all</value>
|
||||||
|
</data>
|
||||||
|
<data name="CloseWindowWarningTitle" xml:space="preserve">
|
||||||
|
<value>Do you want to close all tabs?</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
|
@ -184,6 +184,29 @@ namespace winrt::TerminalApp::implementation
|
||||||
_showDialogHandlers(*this, dialog);
|
_showDialogHandlers(*this, dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Displays a dialog for warnings found while closing the terminal app using
|
||||||
|
// key binding with multiple tabs opened. Display messages to warn user
|
||||||
|
// that more than 1 tab is opend, and once the user clicks the OK button, remove
|
||||||
|
// all the tabs and shut down and app. If cancel is clicked, the dialog will close
|
||||||
|
// - Only one dialog can be visible at a time. If another dialog is visible
|
||||||
|
// when this is called, nothing happens. See _ShowDialog for details
|
||||||
|
void TerminalPage::_ShowCloseWarningDialog()
|
||||||
|
{
|
||||||
|
auto title = _resourceLoader->GetLocalizedString(L"CloseWindowWarningTitle");
|
||||||
|
auto primaryButtonText = _resourceLoader->GetLocalizedString(L"CloseAll");
|
||||||
|
auto secondaryButtonText = _resourceLoader->GetLocalizedString(L"Cancel");
|
||||||
|
|
||||||
|
Controls::ContentDialog dialog;
|
||||||
|
dialog.Title(winrt::box_value(title));
|
||||||
|
|
||||||
|
dialog.PrimaryButtonText(primaryButtonText);
|
||||||
|
dialog.SecondaryButtonText(secondaryButtonText);
|
||||||
|
auto token = dialog.PrimaryButtonClick({ this, &TerminalPage::_CloseWarningPrimaryButtonOnClick });
|
||||||
|
|
||||||
|
_showDialogHandlers(*this, dialog);
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Builds the flyout (dropdown) attached to the new tab button, and
|
// - Builds the flyout (dropdown) attached to the new tab button, and
|
||||||
// attaches it to the button. Populates the flyout with one entry per
|
// attaches it to the button. Populates the flyout with one entry per
|
||||||
|
@ -513,6 +536,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
bindings.DuplicateTab({ this, &TerminalPage::_HandleDuplicateTab });
|
bindings.DuplicateTab({ this, &TerminalPage::_HandleDuplicateTab });
|
||||||
bindings.CloseTab({ this, &TerminalPage::_HandleCloseTab });
|
bindings.CloseTab({ this, &TerminalPage::_HandleCloseTab });
|
||||||
bindings.ClosePane({ this, &TerminalPage::_HandleClosePane });
|
bindings.ClosePane({ this, &TerminalPage::_HandleClosePane });
|
||||||
|
bindings.CloseWindow({ this, &TerminalPage::_HandleCloseWindow });
|
||||||
bindings.ScrollUp({ this, &TerminalPage::_HandleScrollUp });
|
bindings.ScrollUp({ this, &TerminalPage::_HandleScrollUp });
|
||||||
bindings.ScrollDown({ this, &TerminalPage::_HandleScrollDown });
|
bindings.ScrollDown({ this, &TerminalPage::_HandleScrollDown });
|
||||||
bindings.NextTab({ this, &TerminalPage::_HandleNextTab });
|
bindings.NextTab({ this, &TerminalPage::_HandleNextTab });
|
||||||
|
@ -603,25 +627,36 @@ namespace winrt::TerminalApp::implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Removes the tab (both TerminalControl and XAML)
|
// - Look for the index of the input tabView in the tabs vector,
|
||||||
|
// and call _RemoveTabViewItemByIndex
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - tabViewItem: the TabViewItem in the TabView that is being removed.
|
// - tabViewItem: the TabViewItem in the TabView that is being removed.
|
||||||
void TerminalPage::_RemoveTabViewItem(const IInspectable& tabViewItem)
|
void TerminalPage::_RemoveTabViewItem(const IInspectable& tabViewItem)
|
||||||
|
{
|
||||||
|
uint32_t tabIndexFromControl = 0;
|
||||||
|
_tabView.Items().IndexOf(tabViewItem, tabIndexFromControl);
|
||||||
|
|
||||||
|
_RemoveTabViewItemByIndex(tabIndexFromControl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Removes the tab (both TerminalControl and XAML)
|
||||||
|
// Arguments:
|
||||||
|
// - tabIndex: the index of the tab to be removed
|
||||||
|
void TerminalPage::_RemoveTabViewItemByIndex(uint32_t tabIndex)
|
||||||
{
|
{
|
||||||
// To close the window here, we need to close the hosting window.
|
// To close the window here, we need to close the hosting window.
|
||||||
if (_tabs.size() == 1)
|
if (_tabs.size() == 1)
|
||||||
{
|
{
|
||||||
_lastTabClosedHandlers(*this, nullptr);
|
_lastTabClosedHandlers(*this, nullptr);
|
||||||
}
|
}
|
||||||
uint32_t tabIndexFromControl = 0;
|
|
||||||
_tabView.Items().IndexOf(tabViewItem, tabIndexFromControl);
|
|
||||||
auto focusedTabIndex = _GetFocusedTabIndex();
|
|
||||||
|
|
||||||
// Removing the tab from the collection will destroy its control and disconnect its connection.
|
// Removing the tab from the collection will destroy its control and disconnect its connection.
|
||||||
_tabs.erase(_tabs.begin() + tabIndexFromControl);
|
_tabs.erase(_tabs.begin() + tabIndex);
|
||||||
_tabView.Items().RemoveAt(tabIndexFromControl);
|
_tabView.Items().RemoveAt(tabIndex);
|
||||||
|
|
||||||
if (tabIndexFromControl == focusedTabIndex)
|
auto focusedTabIndex = _GetFocusedTabIndex();
|
||||||
|
if (tabIndex == focusedTabIndex)
|
||||||
{
|
{
|
||||||
auto const tabCount = gsl::narrow_cast<decltype(focusedTabIndex)>(_tabs.size());
|
auto const tabCount = gsl::narrow_cast<decltype(focusedTabIndex)>(_tabs.size());
|
||||||
if (focusedTabIndex >= tabCount)
|
if (focusedTabIndex >= tabCount)
|
||||||
|
@ -771,9 +806,8 @@ namespace winrt::TerminalApp::implementation
|
||||||
// - Close the currently focused tab. Focus will move to the left, if possible.
|
// - Close the currently focused tab. Focus will move to the left, if possible.
|
||||||
void TerminalPage::_CloseFocusedTab()
|
void TerminalPage::_CloseFocusedTab()
|
||||||
{
|
{
|
||||||
int focusedTabIndex = _GetFocusedTabIndex();
|
uint32_t focusedTabIndex = _GetFocusedTabIndex();
|
||||||
std::shared_ptr<Tab> focusedTab{ _tabs[focusedTabIndex] };
|
_RemoveTabViewItemByIndex(focusedTabIndex);
|
||||||
_RemoveTabViewItem(focusedTab->GetTabViewItem());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -787,6 +821,32 @@ namespace winrt::TerminalApp::implementation
|
||||||
focusedTab->ClosePane();
|
focusedTab->ClosePane();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Close the terminal app with keys. If there is more
|
||||||
|
// than one tab opened, show a warning dialog.
|
||||||
|
void TerminalPage::_CloseWindow()
|
||||||
|
{
|
||||||
|
if (_tabs.size() > 1)
|
||||||
|
{
|
||||||
|
_ShowCloseWarningDialog();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_CloseAllTabs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Remove all the tabs opened and the terminal will terminate
|
||||||
|
// on its own when the last tab is closed.
|
||||||
|
void TerminalPage::_CloseAllTabs()
|
||||||
|
{
|
||||||
|
while (!_tabs.empty())
|
||||||
|
{
|
||||||
|
_RemoveTabViewItemByIndex(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Move the viewport of the terminal of the currently focused tab up or
|
// - Move the viewport of the terminal of the currently focused tab up or
|
||||||
// down a number of lines. Negative values of `delta` will move the
|
// down a number of lines. Negative values of `delta` will move the
|
||||||
|
@ -1205,6 +1265,20 @@ namespace winrt::TerminalApp::implementation
|
||||||
eventArgs.Cancel(true);
|
eventArgs.Cancel(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Called when the primary button of the content dialog is clicked.
|
||||||
|
// This calls _CloseAllTabs(), which closes all the tabs currently
|
||||||
|
// opened and then the Terminal app. This method will be called if
|
||||||
|
// the user confirms to close all the tabs.
|
||||||
|
// Arguments:
|
||||||
|
// - sender: unused
|
||||||
|
// - ContentDialogButtonClickEventArgs: unused
|
||||||
|
void TerminalPage::_CloseWarningPrimaryButtonOnClick(Windows::UI::Xaml::Controls::ContentDialog /* sender */,
|
||||||
|
Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs /* eventArgs*/)
|
||||||
|
{
|
||||||
|
_CloseAllTabs();
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Hook up keybindings, and refresh the UI of the terminal.
|
// - Hook up keybindings, and refresh the UI of the terminal.
|
||||||
// This includes update the settings of all the tabs according
|
// This includes update the settings of all the tabs according
|
||||||
|
|
|
@ -61,6 +61,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
std::shared_ptr<ScopedResourceLoader> _resourceLoader{ nullptr };
|
std::shared_ptr<ScopedResourceLoader> _resourceLoader{ nullptr };
|
||||||
|
|
||||||
void _ShowAboutDialog();
|
void _ShowAboutDialog();
|
||||||
|
void _ShowCloseWarningDialog();
|
||||||
|
|
||||||
void _CreateNewTabFlyout();
|
void _CreateNewTabFlyout();
|
||||||
void _OpenNewTabDropdown();
|
void _OpenNewTabDropdown();
|
||||||
|
@ -71,6 +72,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
void _SettingsButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
void _SettingsButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||||
void _FeedbackButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
void _FeedbackButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||||
void _AboutButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
void _AboutButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||||
|
void _CloseWarningPrimaryButtonOnClick(Windows::UI::Xaml::Controls::ContentDialog sender, Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs eventArgs);
|
||||||
|
|
||||||
void _HookupKeyBindings(TerminalApp::AppKeyBindings bindings) noexcept;
|
void _HookupKeyBindings(TerminalApp::AppKeyBindings bindings) noexcept;
|
||||||
|
|
||||||
|
@ -79,6 +81,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
void _UpdateTabView();
|
void _UpdateTabView();
|
||||||
void _DuplicateTabViewItem();
|
void _DuplicateTabViewItem();
|
||||||
void _RemoveTabViewItem(const IInspectable& tabViewItem);
|
void _RemoveTabViewItem(const IInspectable& tabViewItem);
|
||||||
|
void _RemoveTabViewItemByIndex(uint32_t tabIndex);
|
||||||
|
|
||||||
void _RegisterTerminalEvents(Microsoft::Terminal::TerminalControl::TermControl term, std::shared_ptr<Tab> hostingTab);
|
void _RegisterTerminalEvents(Microsoft::Terminal::TerminalControl::TermControl term, std::shared_ptr<Tab> hostingTab);
|
||||||
|
|
||||||
|
@ -91,6 +94,8 @@ namespace winrt::TerminalApp::implementation
|
||||||
void _SetFocusedTabIndex(int tabIndex);
|
void _SetFocusedTabIndex(int tabIndex);
|
||||||
void _CloseFocusedTab();
|
void _CloseFocusedTab();
|
||||||
void _CloseFocusedPane();
|
void _CloseFocusedPane();
|
||||||
|
void _CloseWindow();
|
||||||
|
void _CloseAllTabs();
|
||||||
|
|
||||||
// Todo: add more event implementations here
|
// Todo: add more event implementations here
|
||||||
// MSFT:20641986: Add keybindings for New Window
|
// MSFT:20641986: Add keybindings for New Window
|
||||||
|
@ -142,6 +147,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
void _HandleResizePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
void _HandleResizePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||||
void _HandleMoveFocus(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
void _HandleMoveFocus(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||||
void _HandleCopyText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
void _HandleCopyText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
|
||||||
|
void _HandleCloseWindow(const IInspectable&, const TerminalApp::ActionEventArgs& args);
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue