Compare commits

...

9 Commits

Author SHA1 Message Date
Carlos Zamora
9f06016864 code format 2026-04-01 19:49:50 -07:00
Carlos Zamora
aba027ff5c Polish interactions with "close all...tabs/panes" actions
Scenarios covered:
- "close all other panes"
- "close all other tabs"
- "close all tabs after the current tab"

Changes:
- display the dialog appropriately with the right text
- show only one dialog instead of multiple annoying ones
- add special handling when no other panes/tabs are there to be closed
- update handling for these event handlers (passthrough, if possible)
2026-04-01 19:41:28 -07:00
Carlos Zamora
cb531fe8ef consolidate logic 2026-04-01 19:14:02 -07:00
Carlos Zamora
466ba771ba Make confirmCloseOn an enum instead of enum flag + add checkbox
The checkboxes were added to QuitDialog and CloseAllDialog too.
confirmCloseOn should affect all of these for consistency.
2026-04-01 18:44:08 -07:00
Carlos Zamora
1154428f9c address Dustin's feedback 2026-03-30 17:50:15 -07:00
Carlos Zamora
197969255a address my own feedback 2026-03-30 11:41:04 -07:00
Mike Griese
34e973fd18 better styling 2026-03-05 10:14:53 -06:00
Mike Griese
f990fc2fbb format 2026-03-05 10:00:59 -06:00
Mike Griese
da1d3224a1 Add support for more nuanced "closeOn" settings 2026-03-05 09:42:48 -06:00
20 changed files with 352 additions and 75 deletions

View File

@@ -801,7 +801,7 @@ namespace winrt::TerminalApp::implementation
_RemoveTabs(tabsToRemove);
actionArgs.Handled(true);
actionArgs.Handled(!tabsToRemove.empty());
}
}
@@ -837,7 +837,7 @@ namespace winrt::TerminalApp::implementation
// tab row, until you mouse over them. Probably has something to do
// with tabs not resizing down until there's a mouse exit event.
actionArgs.Handled(true);
actionArgs.Handled(!tabsToRemove.empty());
}
}

View File

@@ -496,24 +496,48 @@
<value>Third-Party notices</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>Close all</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Do you want to close all windows?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Close all</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Do you want to close all tabs?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Close all</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Do you want to close this tab?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Close tab</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Do you want to close this pane?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Close pane</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Do you want to close these tabs?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Close tabs</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Do you want to close these panes?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>Close panes</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Don't ask me again</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Cancel</value>
</data>

View File

@@ -391,10 +391,12 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Removes the tab (both TerminalControl and XAML) after prompting for approval
// - Removes the tab (both TerminalControl and XAML) after prompting for approval.
// Arguments:
// - tab: the tab to remove
winrt::Windows::Foundation::IAsyncAction TerminalPage::_HandleCloseTabRequested(winrt::TerminalApp::Tab tab)
// - tab: the tab to remove.
// - skipConfirmClose: if true, skip the confirmCloseOn check. Used when
// an aggregate confirmation has already been shown (e.g. close other tabs).
winrt::Windows::Foundation::IAsyncAction TerminalPage::_HandleCloseTabRequested(winrt::TerminalApp::Tab tab, bool skipConfirmClose)
{
winrt::com_ptr<TerminalPage> strong;
@@ -413,6 +415,24 @@ namespace winrt::TerminalApp::implementation
}
}
// Skip the per-tab confirmCloseOn check when the caller has already
// shown an aggregate confirmation dialog (e.g. _RemoveTabs).
if (!skipConfirmClose)
{
const auto tabImpl = _GetTabImpl(tab);
if (tabImpl && _ShouldWarnOnCloseTab(tabImpl))
{
const auto weak = get_weak();
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::Tab);
strong = weak.get();
if (!strong || warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
}
auto t = winrt::get_self<implementation::Tab>(tab);
auto actions = t->BuildStartupActions(BuildStartupKind::None);
_AddPreviouslyClosedPaneOrTab(std::move(actions));
@@ -782,6 +802,22 @@ namespace winrt::TerminalApp::implementation
if (const auto pane{ activeTab->GetActivePane() })
{
const auto weak = get_weak();
// Check if we should warn before closing a single pane
// (only triggers on Always — Automatic doesn't warn for single pane)
const auto setting = _settings.GlobalSettings().ConfirmCloseOn();
if (setting == ConfirmCloseOn::Always)
{
// If this is the last pane, closing it closes the tab,
// so use the tab dialog text instead.
const auto kind = activeTab->GetLeafPaneCount() == 1 ? ConfirmCloseDialogKind::Tab : ConfirmCloseDialogKind::Pane;
auto warningResult = co_await _ShowConfirmCloseDialog(kind);
if (!weak.get() || warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
if (co_await _PaneConfirmCloseReadOnly(pane))
{
if (const auto strong = weak.get())
@@ -794,15 +830,38 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Close all panes with the given IDs sequentially.
// - Closes provided panes one by one, showing a single aggregate
// confirmation dialog upfront if the confirmCloseOn setting warrants it.
// Arguments:
// - weakTab: weak reference to the tab that the pane belongs to.
// - weakTab: weak reference to the tab that the panes belong to.
// - paneIds: collection of the IDs of the panes that are marked for removal.
void TerminalPage::_ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds)
safe_void_coroutine TerminalPage::_ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds)
{
// Show a single aggregate confirmation for closing multiple panes.
if (_settings.GlobalSettings().ConfirmCloseOn() != ConfirmCloseOn::Never)
{
const auto weak = get_weak();
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::MultiplePanes);
if (!weak.get() || warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
_CloseRemainingPanes(weakTab, std::move(paneIds));
}
// Method Description:
// - Recursively closes panes by ID, chaining each close via the
// ClosedByParent callback. Called after confirmation has already
// been handled by _ClosePanes.
// Arguments:
// - weakTab: weak reference to the tab that the panes belong to.
// - paneIds: remaining pane IDs to close.
void TerminalPage::_CloseRemainingPanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds)
{
if (auto strongTab{ weakTab.get() })
{
// Close all unfocused panes one by one
while (!paneIds.empty())
{
const auto id = paneIds.back();
@@ -813,11 +872,10 @@ namespace winrt::TerminalApp::implementation
pane->ClosedByParent([ids{ std::move(paneIds) }, weakThis{ get_weak() }, weakTab]() {
if (auto strongThis{ weakThis.get() })
{
strongThis->_ClosePanes(weakTab, std::move(ids));
strongThis->_CloseRemainingPanes(weakTab, std::move(ids));
}
});
// Close the pane which will eventually trigger the closed by parent event
_HandleClosePaneRequested(pane);
break;
}
@@ -840,19 +898,35 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Closes provided tabs one by one
// - Closes provided tabs one by one, showing a single aggregate
// confirmation dialog upfront if the confirmCloseOn setting warrants it.
// Arguments:
// - tabs - tabs to remove
safe_void_coroutine TerminalPage::_RemoveTabs(const std::vector<winrt::TerminalApp::Tab> tabs)
{
if (tabs.empty())
{
co_return;
}
const auto weak = get_weak();
// Show a single aggregate confirmation instead of per-tab dialogs.
if (_settings.GlobalSettings().ConfirmCloseOn() != ConfirmCloseOn::Never)
{
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::MultipleTabs);
if (!weak.get() || warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
for (auto& tab : tabs)
{
winrt::Windows::Foundation::IAsyncAction action{ nullptr };
if (const auto strong = weak.get())
{
action = _HandleCloseTabRequested(tab);
action = _HandleCloseTabRequested(tab, true);
}
if (!action)

View File

@@ -884,26 +884,63 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Displays a dialog to warn the user that they are about to close all open windows.
// Once the user clicks the OK button, shut down the application.
// If cancel is clicked, the dialog will close.
// - Displays the unified close confirmation dialog configured for the
// given scenario. Resets the "don't ask me again" checkbox before showing.
// If the user confirms and checked "don't ask me again", sets
// confirmCloseOn to Never and writes settings to disk.
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens. See _ShowDialog for details
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowQuitDialog()
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowConfirmCloseDialog(ConfirmCloseDialogKind kind)
{
return _ShowDialogHelper(L"QuitDialog");
}
// Load the dialog (triggers x:Load) and configure its strings.
const auto dialog = FindName(L"ConfirmCloseDialog").as<ContentDialog>();
switch (kind)
{
case ConfirmCloseDialogKind::CloseAll:
dialog.Title(winrt::box_value(RS_(L"ConfirmCloseDialog_CloseAllTitle")));
dialog.PrimaryButtonText(RS_(L"ConfirmCloseDialog_CloseAllPrimary"));
break;
case ConfirmCloseDialogKind::Window:
dialog.Title(winrt::box_value(RS_(L"ConfirmCloseDialog_WindowTitle")));
dialog.PrimaryButtonText(RS_(L"ConfirmCloseDialog_WindowPrimary"));
break;
case ConfirmCloseDialogKind::Tab:
dialog.Title(winrt::box_value(RS_(L"ConfirmCloseDialog_TabTitle")));
dialog.PrimaryButtonText(RS_(L"ConfirmCloseDialog_TabPrimary"));
break;
case ConfirmCloseDialogKind::MultiplePanes:
dialog.Title(winrt::box_value(RS_(L"ConfirmCloseDialog_MultiplePanesTitle")));
dialog.PrimaryButtonText(RS_(L"ConfirmCloseDialog_MultiplePanesPrimary"));
break;
case ConfirmCloseDialogKind::MultipleTabs:
dialog.Title(winrt::box_value(RS_(L"ConfirmCloseDialog_MultipleTabsTitle")));
dialog.PrimaryButtonText(RS_(L"ConfirmCloseDialog_MultipleTabsPrimary"));
break;
case ConfirmCloseDialogKind::Pane:
dialog.Title(winrt::box_value(RS_(L"ConfirmCloseDialog_PaneTitle")));
dialog.PrimaryButtonText(RS_(L"ConfirmCloseDialog_PanePrimary"));
break;
}
dialog.CloseButtonText(RS_(L"ConfirmCloseDialog_Cancel"));
// 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 opened, 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
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowCloseWarningDialog()
{
return _ShowDialogHelper(L"CloseAllDialog");
// BODGY: After a ContentDialog is dismissed, FindName() can no longer
// resolve children inside it. Use Content() to get the checkbox directly.
const auto checkbox = dialog.Content().as<CheckBox>();
checkbox.IsChecked(false);
auto result = ContentDialogResult::None;
if (auto presenter{ _dialogPresenter.get() })
{
result = co_await presenter.ShowDialog(dialog);
}
if (result == ContentDialogResult::Primary && checkbox.IsChecked().Value())
{
_settings.GlobalSettings().ConfirmCloseOn(ConfirmCloseOn::Never);
_settings.WriteSettingsToDisk();
}
co_return result;
}
// Method Description:
@@ -2210,12 +2247,13 @@ namespace winrt::TerminalApp::implementation
// signal that we want to close everything.
safe_void_coroutine TerminalPage::RequestQuit()
{
if (!_displayingCloseDialog)
const auto setting = _settings.GlobalSettings().ConfirmCloseOn();
if (setting != ConfirmCloseOn::Never && !_displayingCloseDialog)
{
_displayingCloseDialog = true;
const auto weak = get_weak();
auto warningResult = co_await _ShowQuitDialog();
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::CloseAll);
const auto strong = weak.get();
if (!strong)
{
@@ -2228,9 +2266,9 @@ namespace winrt::TerminalApp::implementation
{
co_return;
}
QuitRequested.raise(nullptr, nullptr);
}
QuitRequested.raise(nullptr, nullptr);
}
void TerminalPage::PersistState()
@@ -2308,12 +2346,75 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Close the terminal app. If there is more
// than one tab opened, show a warning dialog.
// - Determines whether a close-window action should show a confirmation
// dialog, based on the confirmCloseOn setting and the current window state.
// Arguments:
// - <none>
// Return Value:
// - true if a warning dialog should be shown before closing the window.
bool TerminalPage::_ShouldWarnOnClose() const
{
const auto setting = _settings.GlobalSettings().ConfirmCloseOn();
switch (setting)
{
case ConfirmCloseOn::Always:
return true;
case ConfirmCloseOn::Automatic:
{
// Warn if there's more than one tab.
if (_HasMultipleTabs())
{
return true;
}
// Warn if the one tab has more than one pane.
if (_GetTabImpl(_tabs.GetAt(0))->GetLeafPaneCount() > 1)
{
return true;
}
return false;
}
case ConfirmCloseOn::Never:
default:
return false;
}
}
// Method Description:
// - Determines whether closing a specific tab should show a confirmation
// dialog, based on the confirmCloseOn setting and the tab's state.
// Arguments:
// - tab: The tab being closed.
// Return Value:
// - true if a warning dialog should be shown before closing the tab.
bool TerminalPage::_ShouldWarnOnCloseTab(const winrt::com_ptr<Tab>& tab) const
{
const auto setting = _settings.GlobalSettings().ConfirmCloseOn();
switch (setting)
{
case ConfirmCloseOn::Always:
return true;
case ConfirmCloseOn::Automatic:
// Warn if this tab has more than one pane.
return tab->GetLeafPaneCount() > 1;
case ConfirmCloseOn::Never:
default:
return false;
}
}
// Method Description:
// - Close the terminal app. If the confirmCloseOn setting indicates we should
// warn for the current window state, show a warning dialog.
safe_void_coroutine TerminalPage::CloseWindow()
{
if (_HasMultipleTabs() &&
_settings.GlobalSettings().ConfirmCloseAllTabs() &&
if (_ShouldWarnOnClose() &&
!_displayingCloseDialog)
{
if (_newTabButton && _newTabButton.Flyout())
@@ -2322,7 +2423,14 @@ namespace winrt::TerminalApp::implementation
}
_DismissTabContextMenus();
_displayingCloseDialog = true;
auto warningResult = co_await _ShowCloseWarningDialog();
const auto weak = get_weak();
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::Window);
if (!weak.get())
{
co_return;
}
_displayingCloseDialog = false;
if (warningResult != ContentDialogResult::Primary)

View File

@@ -54,6 +54,16 @@ namespace winrt::TerminalApp::implementation
ScrollDown = 1
};
enum class ConfirmCloseDialogKind
{
Pane,
Tab,
MultiplePanes,
MultipleTabs,
Window,
CloseAll
};
struct RenameWindowRequestedArgs : RenameWindowRequestedArgsT<RenameWindowRequestedArgs>
{
WINRT_PROPERTY(winrt::hstring, ProposedName);
@@ -301,8 +311,7 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowDialogHelper(const std::wstring_view& name);
void _ShowAboutDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowQuitDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCloseWarningDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowConfirmCloseDialog(ConfirmCloseDialogKind kind);
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCloseReadOnlyDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowMultiLinePasteWarningDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowLargePasteWarningDialog();
@@ -349,7 +358,7 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine _ExportTab(const Tab& tab, winrt::hstring filepath);
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::Tab tab);
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::Tab tab, bool skipConfirmClose = false);
void _CloseTabAtIndex(uint32_t index);
void _RemoveTab(const winrt::TerminalApp::Tab& tab);
safe_void_coroutine _RemoveTabs(const std::vector<winrt::TerminalApp::Tab> tabs);
@@ -400,9 +409,12 @@ namespace winrt::TerminalApp::implementation
TerminalApp::Tab _GetTabByTabViewItem(const IInspectable& tabViewItem) const noexcept;
void _HandleClosePaneRequested(std::shared_ptr<Pane> pane);
bool _ShouldWarnOnClose() const;
bool _ShouldWarnOnCloseTab(const winrt::com_ptr<Tab>& tab) const;
safe_void_coroutine _SetFocusedTab(const winrt::TerminalApp::Tab tab);
safe_void_coroutine _CloseFocusedPane();
void _ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds);
safe_void_coroutine _ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds);
void _CloseRemainingPanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds);
winrt::Windows::Foundation::IAsyncOperation<bool> _PaneConfirmCloseReadOnly(std::shared_ptr<Pane> pane);
void _AddPreviouslyClosedPaneOrTab(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>&& args);

View File

@@ -86,17 +86,12 @@
Grid.Row="2"
x:Load="False" />
<ContentDialog x:Name="QuitDialog"
x:Uid="QuitDialog"
<ContentDialog x:Name="ConfirmCloseDialog"
Grid.Row="2"
x:Load="False"
DefaultButton="Primary" />
<ContentDialog x:Name="CloseAllDialog"
x:Uid="CloseAllDialog"
Grid.Row="2"
x:Load="False"
DefaultButton="Primary" />
DefaultButton="Primary">
<CheckBox x:Uid="DontAskAgainCheckBox" />
</ContentDialog>
<ContentDialog x:Name="CloseReadOnlyDialog"
x:Uid="CloseReadOnlyDialog"

View File

@@ -135,11 +135,14 @@
<TextBlock x:Uid="Globals_WarningsHeader"
Style="{StaticResource TextBlockSubHeaderStyle}" />
<!-- Close All Tabs Warning -->
<local:SettingContainer x:Name="ConfirmCloseAllTabs"
x:Uid="Globals_ConfirmCloseAllTabs">
<ToggleSwitch IsOn="{x:Bind ViewModel.ConfirmCloseAllTabs, Mode=TwoWay}"
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
<!-- Confirm Close On -->
<local:SettingContainer x:Name="ConfirmCloseOn"
x:Uid="Globals_ConfirmCloseOn">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind ViewModel.ConfirmCloseOnList}"
SelectedItem="{x:Bind ViewModel.CurrentConfirmCloseOn, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- Input Service Warning -->

View File

@@ -17,5 +17,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
INITIALIZE_BINDABLE_ENUM_SETTING(TabSwitcherMode, TabSwitcherMode, TabSwitcherMode, L"Globals_TabSwitcherMode", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(CopyFormat, CopyFormat, winrt::Microsoft::Terminal::Control::CopyFormat, L"Globals_CopyFormat", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(ConfirmCloseOn, ConfirmCloseOn, Model::ConfirmCloseOn, L"Globals_ConfirmCloseOn", L"Content");
}
}

View File

@@ -19,6 +19,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
GETSET_BINDABLE_ENUM_SETTING(TabSwitcherMode, Model::TabSwitcherMode, _GlobalSettings.TabSwitcherMode);
GETSET_BINDABLE_ENUM_SETTING(CopyFormat, winrt::Microsoft::Terminal::Control::CopyFormat, _GlobalSettings.CopyFormatting);
GETSET_BINDABLE_ENUM_SETTING(ConfirmCloseOn, Model::ConfirmCloseOn, _GlobalSettings.ConfirmCloseOn);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, CopyOnSelect);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, TrimBlockSelection);
@@ -30,7 +31,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, DetectURLs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, SearchWebDefaultQueryUrl);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, WordDelimiters);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ConfirmCloseAllTabs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, InputServiceWarning);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, WarnAboutLargePaste);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, WarnAboutMultiLinePaste);

View File

@@ -12,10 +12,13 @@ namespace Microsoft.Terminal.Settings.Editor
InteractionViewModel(Microsoft.Terminal.Settings.Model.GlobalAppSettings globalSettings);
IInspectable CurrentTabSwitcherMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> TabSwitcherModeList { get; };
Windows.Foundation.Collections.IObservableVector<EnumEntry> TabSwitcherModeList { get; };
IInspectable CurrentCopyFormat;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> CopyFormatList { get; };
Windows.Foundation.Collections.IObservableVector<EnumEntry> CopyFormatList { get; };
IInspectable CurrentConfirmCloseOn;
Windows.Foundation.Collections.IObservableVector<EnumEntry> ConfirmCloseOnList { get; };
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, CopyOnSelect);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, TrimBlockSelection);
@@ -27,7 +30,6 @@ namespace Microsoft.Terminal.Settings.Editor
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, DetectURLs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(String, SearchWebDefaultQueryUrl);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(String, WordDelimiters);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ConfirmCloseAllTabs);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, InputServiceWarning);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, WarnAboutLargePaste);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Microsoft.Terminal.Control.WarnAboutMultiLinePaste, WarnAboutMultiLinePaste);

View File

@@ -2197,6 +2197,26 @@
<value>Warn when closing more than one tab</value>
<comment>Header for a control to toggle whether to show a confirm dialog box when closing the application with multiple tabs open.</comment>
</data>
<data name="Globals_ConfirmCloseOn.Header" xml:space="preserve">
<value>Warn when closing</value>
<comment>Header for a dropdown controlling when to show a confirmation dialog before closing.</comment>
</data>
<data name="Globals_ConfirmCloseOn.HelpText" xml:space="preserve">
<value>Controls when a confirmation dialog appears before closing tabs or windows. "Always" presents the dialog when closing any pane.</value>
<comment>Help text associated with Globals_ConfirmCloseOn. "Always" refers to Globals_ConfirmCloseOnAlways.Content.</comment>
</data>
<data name="Globals_ConfirmCloseOnNever.Content" xml:space="preserve">
<value>Never</value>
<comment>Option associated with Globals_ConfirmCloseOn. "Never" means that the system will never display a warning when closing.</comment>
</data>
<data name="Globals_ConfirmCloseOnAlways.Content" xml:space="preserve">
<value>Always</value>
<comment>Option associated with Globals_ConfirmCloseOn. "Always" means that the system will always display a warning when closing.</comment>
</data>
<data name="Globals_ConfirmCloseOnAutomatic.Content" xml:space="preserve">
<value>Multiple tabs or panes</value>
<comment>Option associated with Globals_ConfirmCloseOn. The system will display a warning when multiple tabs or panes are present.</comment>
</data>
<data name="Globals_InputServiceWarning.Header" xml:space="preserve">
<value>Warn when "Touch Keyboard and Handwriting Panel Service" is disabled</value>
</data>

View File

@@ -43,6 +43,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::TextMeasurement, TextMeasurement);
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::AmbiguousWidth, AmbiguousWidth);
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::WarnAboutMultiLinePaste, WarnAboutMultiLinePaste);
DEFINE_ENUM_MAP(Model::ConfirmCloseOn, ConfirmCloseOn);
// Profile Settings
DEFINE_ENUM_MAP(Model::CloseOnExitMode, CloseOnExitMode);

View File

@@ -40,6 +40,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::TextMeasurement> TextMeasurement();
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::AmbiguousWidth> AmbiguousWidth();
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::WarnAboutMultiLinePaste> WarnAboutMultiLinePaste();
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, ConfirmCloseOn> ConfirmCloseOn();
// Profile Settings
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, CloseOnExitMode> CloseOnExitMode();

View File

@@ -22,6 +22,7 @@ namespace Microsoft.Terminal.Settings.Model
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.TextMeasurement> TextMeasurement { get; };
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.AmbiguousWidth> AmbiguousWidth { get; };
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.WarnAboutMultiLinePaste> WarnAboutMultiLinePaste { get; };
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Settings.Model.ConfirmCloseOn> ConfirmCloseOn { get; };
// Profile Settings
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Settings.Model.CloseOnExitMode> CloseOnExitMode { get; };

View File

@@ -160,7 +160,16 @@ void GlobalAppSettings::LayerJson(const Json::Value& json, const OriginTag origi
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyInputServiceWarningKey, _InputServiceWarning) || _fixupsAppliedDuringLoad;
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyWarnAboutLargePasteKey, _WarnAboutLargePaste) || _fixupsAppliedDuringLoad;
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyWarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste) || _fixupsAppliedDuringLoad;
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyConfirmCloseAllTabsKey, _ConfirmCloseAllTabs) || _fixupsAppliedDuringLoad;
// GH#6549 - Migrate legacy "confirmCloseAllTabs" boolean to the new
// "confirmCloseOn" enum. true -> Automatic, false -> Never.
{
std::optional<bool> legacyConfirmClose;
if (JsonUtils::GetValueForKey(json, LegacyConfirmCloseAllTabsKey, legacyConfirmClose))
{
_ConfirmCloseOn = legacyConfirmClose.value() ? ConfirmCloseOn::Automatic : ConfirmCloseOn::Never;
_fixupsAppliedDuringLoad = true;
}
}
#define GLOBAL_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
JsonUtils::GetValueForKey(json, jsonKey, _##name); \

View File

@@ -50,6 +50,13 @@ namespace Microsoft.Terminal.Settings.Model
AfterCurrentTab,
};
enum ConfirmCloseOn
{
Never = 0,
Automatic = 1,
Always = 2,
};
[default_interface] runtimeclass GlobalAppSettings {
Guid DefaultProfile;
@@ -61,7 +68,7 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_SETTING(Boolean, ShowTabsFullscreen);
INHERITABLE_SETTING(NewTabPosition, NewTabPosition);
INHERITABLE_SETTING(Boolean, ShowTitleInTitlebar);
INHERITABLE_SETTING(Boolean, ConfirmCloseAllTabs);
INHERITABLE_SETTING(ConfirmCloseOn, ConfirmCloseOn);
INHERITABLE_SETTING(String, Language);
INHERITABLE_SETTING(Microsoft.UI.Xaml.Controls.TabViewWidthMode, TabWidthMode);
INHERITABLE_SETTING(Boolean, UseAcrylicInTabRow);

View File

@@ -38,7 +38,7 @@ Author(s):
X(bool, AlwaysShowTabs, "alwaysShowTabs", true) \
X(Model::NewTabPosition, NewTabPosition, "newTabPosition", Model::NewTabPosition::AfterLastTab) \
X(bool, ShowTitleInTitlebar, "showTerminalTitleInTitlebar", true) \
X(bool, ConfirmCloseAllTabs, "warning.confirmCloseAllTabs", true) \
X(Model::ConfirmCloseOn, ConfirmCloseOn, "warning.confirmCloseOn", Model::ConfirmCloseOn::Automatic) \
X(Model::ThemePair, Theme, "theme") \
X(hstring, Language, "language") \
X(winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, "tabWidthMode", winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal) \

View File

@@ -88,6 +88,25 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::MatchMode)
};
};
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::ConfirmCloseOn)
{
JSON_MAPPINGS(3) = {
pair_type{ "never", ValueType::Never },
pair_type{ "always", ValueType::Always },
pair_type{ "automatic", ValueType::Automatic },
};
auto FromJson(const Json::Value& json)
{
return BaseEnumMapper::FromJson(json);
}
bool CanConvert(const Json::Value& json)
{
return BaseEnumMapper::CanConvert(json);
}
};
JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::BellStyle)
{
static constexpr std::array<pair_type, 6> mappings = {

View File

@@ -24,7 +24,7 @@
"showAdminShield": true,
// Miscellaneous
"confirmCloseAllTabs": true,
"warning.confirmCloseOn": "automatic",
"theme": "dark",
"snapToGridOnResize": true,
"disableAnimations": false,

View File

@@ -125,7 +125,7 @@ namespace SettingsModelUnitTests
"trimPaste": true,
"warning.confirmCloseAllTabs" : true,
"warning.confirmCloseOn": "automatic",
"warning.inputService" : true,
"warning.largePaste" : true,
"warning.multiLinePaste" : "automatic",