Compare commits

...

7 Commits

Author SHA1 Message Date
Carlos Zamora
730a8eb3c5 Update state when warning enabled through SUI 2026-03-30 18:23:08 -07:00
Carlos Zamora
1bcd2e4d4f Add "Don't ask me again" checkbox to close warnings 2026-03-30 18:18:02 -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
18 changed files with 452 additions and 18 deletions

View File

@@ -514,6 +514,27 @@
<data name="CloseAllDialog.Title" xml:space="preserve">
<value>Do you want to close all tabs?</value>
</data>
<data name="CloseTabDialog.CloseButtonText" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="CloseTabDialog.PrimaryButtonText" xml:space="preserve">
<value>Close tab</value>
</data>
<data name="CloseTabDialog.Title" xml:space="preserve">
<value>Do you want to close this tab?</value>
</data>
<data name="ClosePaneDialog.CloseButtonText" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="ClosePaneDialog.PrimaryButtonText" xml:space="preserve">
<value>Close pane</value>
</data>
<data name="ClosePaneDialog.Title" xml:space="preserve">
<value>Do you want to close this pane?</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

@@ -413,6 +413,51 @@ namespace winrt::TerminalApp::implementation
}
}
// Check if we should warn before closing this tab based on the
// confirmCloseOn flags (e.g. multiple panes, always, etc.)
{
const auto tabImpl = _GetTabImpl(tab);
const auto reason = tabImpl ? _ShouldWarnOnCloseTab(tabImpl) : ConfirmCloseOn::Never;
if (reason != ConfirmCloseOn::Never)
{
const auto weak = get_weak();
// Show the "don't ask me again" checkbox only when the dialog
// is triggered by conditional flags (not just Always).
const auto conditionalFlags = reason & ~ConfirmCloseOn::Always;
const auto showCheckbox = conditionalFlags != ConfirmCloseOn::Never;
// Load the dialog (triggers x:Load) so we can configure the
// checkbox before showing it.
const auto dialog = FindName(L"CloseTabDialog").try_as<ContentDialog>();
const auto checkbox = dialog ? dialog.Content().try_as<CheckBox>() : nullptr;
if (checkbox)
{
checkbox.IsChecked(false);
checkbox.Visibility(showCheckbox ? Visibility::Visible : Visibility::Collapsed);
}
auto warningResult = co_await _ShowCloseTabWarningDialog();
strong = weak.get();
if (!strong || warningResult != ContentDialogResult::Primary)
{
co_return;
}
// Persist dismissal if the user checked "don't ask me again"
if (showCheckbox && checkbox && checkbox.IsChecked().Value())
{
const auto state = ApplicationState::SharedInstance();
if (WI_IsFlagSet(reason, ConfirmCloseOn::MultiplePanes))
{
state.DismissedConfirmCloseMultiplePanes(true);
}
}
}
}
auto t = winrt::get_self<implementation::Tab>(tab);
auto actions = t->BuildStartupActions(BuildStartupKind::None);
_AddPreviouslyClosedPaneOrTab(std::move(actions));
@@ -782,6 +827,32 @@ 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 — or MultipleProcesses in the future)
const auto flags = _settings.GlobalSettings().ConfirmCloseOn();
if (WI_IsFlagSet(flags, ConfirmCloseOn::Always))
{
// The "don't ask me again" checkbox stays collapsed for
// Always-only triggers. It will become relevant when
// MultipleProcesses is implemented.
// Load the dialog (triggers x:Load) to configure the checkbox.
const auto dialog = FindName(L"ClosePaneDialog").try_as<ContentDialog>();
if (const auto checkbox = dialog ? dialog.Content().try_as<CheckBox>() : nullptr)
{
checkbox.IsChecked(false);
checkbox.Visibility(Visibility::Collapsed);
}
auto warningResult = co_await _ShowClosePaneWarningDialog();
if (warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
// TODO GH#6549: ConfirmCloseOn::MultipleProcesses check here
// When implemented, show the checkbox and persist dismissal state.
if (co_await _PaneConfirmCloseReadOnly(pane))
{
if (const auto strong = weak.get())

View File

@@ -906,6 +906,22 @@ namespace winrt::TerminalApp::implementation
return _ShowDialogHelper(L"CloseAllDialog");
}
// Method Description:
// - Displays a dialog for warnings found while closing a tab that has
// multiple panes or other conditions that warrant a warning.
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowCloseTabWarningDialog()
{
return _ShowDialogHelper(L"CloseTabDialog");
}
// Method Description:
// - Displays a dialog for warnings found while closing a single pane
// (e.g. when confirmCloseOn includes "always").
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowClosePaneWarningDialog()
{
return _ShowDialogHelper(L"ClosePaneDialog");
}
// Method Description:
// - Displays a dialog for warnings found while closing the terminal tab marked as read-only
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowCloseReadOnlyDialog()
@@ -2308,12 +2324,99 @@ 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 flags and the current window state.
// Arguments:
// - <none>
// Return Value:
// - The ConfirmCloseOn flags that triggered the warning, or Never if no
// warning is needed. Callers use this to determine checkbox visibility
// and which dismissal state to persist.
ConfirmCloseOn TerminalPage::_ShouldWarnOnClose() const
{
auto result = ConfirmCloseOn::Never;
const auto flags = _settings.GlobalSettings().ConfirmCloseOn();
// Always flag means warn unconditionally.
if (WI_IsFlagSet(flags, ConfirmCloseOn::Always))
{
WI_SetFlag(result, ConfirmCloseOn::Always);
}
// MultipleTabs: warn if there's more than one tab and the user hasn't
// dismissed this warning via "don't ask me again".
if (WI_IsFlagSet(flags, ConfirmCloseOn::MultipleTabs) &&
_HasMultipleTabs() &&
!ApplicationState::SharedInstance().DismissedConfirmCloseMultipleTabs())
{
WI_SetFlag(result, ConfirmCloseOn::MultipleTabs);
}
// MultiplePanes: warn if any tab has more than one pane and the user
// hasn't dismissed this warning via "don't ask me again".
if (WI_IsFlagSet(flags, ConfirmCloseOn::MultiplePanes) &&
!ApplicationState::SharedInstance().DismissedConfirmCloseMultiplePanes())
{
for (const auto tab : _tabs)
{
if (const auto impl = _GetTabImpl(tab))
{
if (impl->GetLeafPaneCount() > 1)
{
WI_SetFlag(result, ConfirmCloseOn::MultiplePanes);
break;
}
}
}
}
// TODO GH#6549: ConfirmCloseOn::MultipleProcesses
// Needs TermControl to expose whether >1 client process is connected.
return result;
}
// Method Description:
// - Determines whether closing a specific tab should show a confirmation
// dialog, based on the confirmCloseOn flags and the tab's state.
// Arguments:
// - tab: The tab being closed.
// Return Value:
// - The ConfirmCloseOn flags that triggered the warning, or Never if no
// warning is needed.
ConfirmCloseOn TerminalPage::_ShouldWarnOnCloseTab(const winrt::com_ptr<Tab>& tab) const
{
auto result = ConfirmCloseOn::Never;
const auto flags = _settings.GlobalSettings().ConfirmCloseOn();
// Always flag means warn unconditionally.
if (WI_IsFlagSet(flags, ConfirmCloseOn::Always))
{
WI_SetFlag(result, ConfirmCloseOn::Always);
}
// MultiplePanes: warn if this tab has more than one pane and the user
// hasn't dismissed this warning via "don't ask me again".
if (WI_IsFlagSet(flags, ConfirmCloseOn::MultiplePanes) &&
tab->GetLeafPaneCount() > 1 &&
!ApplicationState::SharedInstance().DismissedConfirmCloseMultiplePanes())
{
WI_SetFlag(result, ConfirmCloseOn::MultiplePanes);
}
// TODO GH#6549: ConfirmCloseOn::MultipleProcesses
// Needs TermControl to expose whether >1 client process is connected.
return result;
}
// Method Description:
// - Close the terminal app. If the confirmCloseOn flags indicate we should
// warn for the current window state, show a warning dialog.
safe_void_coroutine TerminalPage::CloseWindow()
{
if (_HasMultipleTabs() &&
_settings.GlobalSettings().ConfirmCloseAllTabs() &&
const auto reason = _ShouldWarnOnClose();
if (reason != ConfirmCloseOn::Never &&
!_displayingCloseDialog)
{
if (_newTabButton && _newTabButton.Flyout())
@@ -2322,6 +2425,22 @@ namespace winrt::TerminalApp::implementation
}
_DismissTabContextMenus();
_displayingCloseDialog = true;
// Show the "don't ask me again" checkbox only when the dialog is
// triggered by conditional flags (not just Always).
const auto conditionalFlags = reason & ~ConfirmCloseOn::Always;
const auto showCheckbox = conditionalFlags != ConfirmCloseOn::Never;
// Load the dialog (triggers x:Load) so we can configure the checkbox
// before showing it.
const auto dialog = FindName(L"CloseAllDialog").try_as<WUX::Controls::ContentDialog>();
const auto checkbox = dialog ? dialog.Content().try_as<WUX::Controls::CheckBox>() : nullptr;
if (checkbox)
{
checkbox.IsChecked(false);
checkbox.Visibility(showCheckbox ? WUX::Visibility::Visible : WUX::Visibility::Collapsed);
}
auto warningResult = co_await _ShowCloseWarningDialog();
_displayingCloseDialog = false;
@@ -2329,6 +2448,20 @@ namespace winrt::TerminalApp::implementation
{
co_return;
}
// Persist dismissal if the user checked "don't ask me again"
if (showCheckbox && checkbox && checkbox.IsChecked().Value())
{
const auto state = ApplicationState::SharedInstance();
if (WI_IsFlagSet(reason, ConfirmCloseOn::MultipleTabs))
{
state.DismissedConfirmCloseMultipleTabs(true);
}
if (WI_IsFlagSet(reason, ConfirmCloseOn::MultiplePanes))
{
state.DismissedConfirmCloseMultiplePanes(true);
}
}
}
CloseWindowRequested.raise(*this, nullptr);

View File

@@ -303,6 +303,8 @@ namespace winrt::TerminalApp::implementation
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> _ShowCloseTabWarningDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowClosePaneWarningDialog();
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();
@@ -400,6 +402,8 @@ namespace winrt::TerminalApp::implementation
TerminalApp::Tab _GetTabByTabViewItem(const IInspectable& tabViewItem) const noexcept;
void _HandleClosePaneRequested(std::shared_ptr<Pane> pane);
Microsoft::Terminal::Settings::Model::ConfirmCloseOn _ShouldWarnOnClose() const;
Microsoft::Terminal::Settings::Model::ConfirmCloseOn _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);

View File

@@ -96,7 +96,31 @@
x:Uid="CloseAllDialog"
Grid.Row="2"
x:Load="False"
DefaultButton="Primary" />
DefaultButton="Primary">
<CheckBox x:Name="CloseAllDontAskAgain"
x:Uid="DontAskAgainCheckBox"
Visibility="Collapsed" />
</ContentDialog>
<ContentDialog x:Name="CloseTabDialog"
x:Uid="CloseTabDialog"
Grid.Row="2"
x:Load="False"
DefaultButton="Primary">
<CheckBox x:Name="CloseTabDontAskAgain"
x:Uid="DontAskAgainCheckBox"
Visibility="Collapsed" />
</ContentDialog>
<ContentDialog x:Name="ClosePaneDialog"
x:Uid="ClosePaneDialog"
Grid.Row="2"
x:Load="False"
DefaultButton="Primary">
<CheckBox x:Name="ClosePaneDontAskAgain"
x:Uid="DontAskAgainCheckBox"
Visibility="Collapsed" />
</ContentDialog>
<ContentDialog x:Name="CloseReadOnlyDialog"
x:Uid="CloseReadOnlyDialog"

View File

@@ -135,11 +135,19 @@
<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"
CurrentValue="{x:Bind ViewModel.ConfirmCloseOnPreview, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Globals_ConfirmCloseOnAlways"
IsChecked="{x:Bind ViewModel.IsConfirmCloseOnFlagSet(1), BindBack=ViewModel.SetConfirmCloseOnAlways, Mode=TwoWay}" />
<CheckBox x:Uid="Globals_ConfirmCloseOnMultipleTabs"
IsChecked="{x:Bind ViewModel.IsConfirmCloseOnFlagSet(2), BindBack=ViewModel.SetConfirmCloseOnMultipleTabs, Mode=TwoWay}" />
<CheckBox x:Uid="Globals_ConfirmCloseOnMultiplePanes"
IsChecked="{x:Bind ViewModel.IsConfirmCloseOnFlagSet(4), BindBack=ViewModel.SetConfirmCloseOnMultiplePanes, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Input Service Warning -->

View File

@@ -6,6 +6,7 @@
#include "InteractionViewModel.g.cpp"
#include "EnumEntry.h"
using namespace winrt::Windows::UI::Xaml::Data;
using namespace winrt::Windows::UI::Xaml::Navigation;
using namespace winrt::Windows::Foundation;
using namespace winrt::Microsoft::Terminal::Settings::Model;
@@ -17,5 +18,91 @@ 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");
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
const auto viewModelProperty{ args.PropertyName() };
if (viewModelProperty == L"ConfirmCloseOn")
{
_NotifyChanges(L"ConfirmCloseOnPreview");
}
});
}
hstring InteractionViewModel::ConfirmCloseOnPreview() const
{
const auto flags = ConfirmCloseOn();
if (WI_IsFlagSet(flags, Model::ConfirmCloseOn::Always))
{
return RS_(L"Globals_ConfirmCloseOnAlways/Content");
}
else if (flags == Model::ConfirmCloseOn::Never)
{
return RS_(L"Globals_ConfirmCloseOnNever");
}
std::vector<hstring> resultList;
resultList.reserve(2);
if (WI_IsFlagSet(flags, Model::ConfirmCloseOn::MultipleTabs))
{
resultList.emplace_back(RS_(L"Globals_ConfirmCloseOnMultipleTabs/Content"));
}
if (WI_IsFlagSet(flags, Model::ConfirmCloseOn::MultiplePanes))
{
resultList.emplace_back(RS_(L"Globals_ConfirmCloseOnMultiplePanes/Content"));
}
hstring result{};
for (auto&& entry : resultList)
{
if (result.empty())
{
result = entry;
}
else
{
result = result + L", " + entry;
}
}
return result;
}
bool InteractionViewModel::IsConfirmCloseOnFlagSet(const uint32_t flag)
{
return (WI_EnumValue(ConfirmCloseOn()) & flag) == flag;
}
void InteractionViewModel::SetConfirmCloseOnAlways(winrt::Windows::Foundation::IReference<bool> on)
{
auto current = ConfirmCloseOn();
WI_UpdateFlag(current, Model::ConfirmCloseOn::Always, winrt::unbox_value<bool>(on));
ConfirmCloseOn(current);
}
void InteractionViewModel::SetConfirmCloseOnMultipleTabs(winrt::Windows::Foundation::IReference<bool> on)
{
auto current = ConfirmCloseOn();
const auto enabled = winrt::unbox_value<bool>(on);
WI_UpdateFlag(current, Model::ConfirmCloseOn::MultipleTabs, enabled);
ConfirmCloseOn(current);
// Reset the dismissed state so the user sees the warning again
if (enabled)
{
ApplicationState::SharedInstance().DismissedConfirmCloseMultipleTabs(false);
}
}
void InteractionViewModel::SetConfirmCloseOnMultiplePanes(winrt::Windows::Foundation::IReference<bool> on)
{
auto current = ConfirmCloseOn();
const auto enabled = winrt::unbox_value<bool>(on);
WI_UpdateFlag(current, Model::ConfirmCloseOn::MultiplePanes, enabled);
ConfirmCloseOn(current);
// Reset the dismissed state so the user sees the warning again
if (enabled)
{
ApplicationState::SharedInstance().DismissedConfirmCloseMultiplePanes(false);
}
}
}

View File

@@ -30,7 +30,12 @@ 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, ConfirmCloseOn);
hstring ConfirmCloseOnPreview() const;
bool IsConfirmCloseOnFlagSet(const uint32_t flag);
void SetConfirmCloseOnAlways(winrt::Windows::Foundation::IReference<bool> on);
void SetConfirmCloseOnMultipleTabs(winrt::Windows::Foundation::IReference<bool> on);
void SetConfirmCloseOnMultiplePanes(winrt::Windows::Foundation::IReference<bool> on);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, InputServiceWarning);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, WarnAboutLargePaste);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, WarnAboutMultiLinePaste);

View File

@@ -27,7 +27,12 @@ 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(Microsoft.Terminal.Settings.Model.ConfirmCloseOn, ConfirmCloseOn);
String ConfirmCloseOnPreview { get; };
Boolean IsConfirmCloseOnFlagSet(UInt32 flag);
void SetConfirmCloseOnAlways(Windows.Foundation.IReference<Boolean> on);
void SetConfirmCloseOnMultipleTabs(Windows.Foundation.IReference<Boolean> on);
void SetConfirmCloseOnMultiplePanes(Windows.Foundation.IReference<Boolean> on);
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>Confirm before closing</value>
<comment>Header for a group of checkboxes controlling when to show a confirmation dialog before closing.</comment>
</data>
<data name="Globals_ConfirmCloseOnAlways.Content" xml:space="preserve">
<value>Always</value>
<comment>Checkbox label: always confirm before closing a window, tab, or pane.</comment>
</data>
<data name="Globals_ConfirmCloseOnMultipleTabs.Content" xml:space="preserve">
<value>Multiple tabs</value>
<comment>Checkbox label: confirm before closing a window with more than one tab.</comment>
</data>
<data name="Globals_ConfirmCloseOnMultiplePanes.Content" xml:space="preserve">
<value>Multiple panes</value>
<comment>Checkbox label: confirm before closing a tab with more than one pane.</comment>
</data>
<data name="Globals_ConfirmCloseOnNever" xml:space="preserve">
<value>Never</value>
<comment>Preview text shown when no confirm-close-on flags are set.</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

@@ -42,7 +42,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
X(FileSource::Shared, Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage>, DismissedMessages, "dismissedMessages") \
X(FileSource::Local, Windows::Foundation::Collections::IVector<hstring>, AllowedCommandlines, "allowedCommandlines") \
X(FileSource::Local, std::unordered_set<hstring>, DismissedBadges, "dismissedBadges") \
X(FileSource::Shared, bool, SSHFolderGenerated, "sshFolderGenerated", false)
X(FileSource::Shared, bool, SSHFolderGenerated, "sshFolderGenerated", false) \
X(FileSource::Shared, bool, DismissedConfirmCloseMultipleTabs, "warning.confirmCloseMultipleTabs", false) \
X(FileSource::Shared, bool, DismissedConfirmCloseMultiplePanes, "warning.confirmCloseMultiplePanes", false)
struct WindowLayout : WindowLayoutT<WindowLayout>
{

View File

@@ -41,5 +41,7 @@ namespace Microsoft.Terminal.Settings.Model
Windows.Foundation.Collections.IVector<String> RecentCommands;
Windows.Foundation.Collections.IVector<InfoBarMessage> DismissedMessages;
Windows.Foundation.Collections.IVector<String> AllowedCommandlines;
Boolean DismissedConfirmCloseMultipleTabs;
Boolean DismissedConfirmCloseMultiplePanes;
}
}

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" flags enum. true -> MultipleTabs|MultiplePanes, false -> Never.
{
std::optional<bool> legacyConfirmClose;
if (JsonUtils::GetValueForKey(json, LegacyConfirmCloseAllTabsKey, legacyConfirmClose))
{
_ConfirmCloseOn = legacyConfirmClose.value() ? winrt::Microsoft::Terminal::Settings::Model::ConfirmCloseOn::MultipleTabs | winrt::Microsoft::Terminal::Settings::Model::ConfirmCloseOn::MultiplePanes : winrt::Microsoft::Terminal::Settings::Model::ConfirmCloseOn::Never;
_fixupsAppliedDuringLoad = true;
}
}
#define GLOBAL_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
JsonUtils::GetValueForKey(json, jsonKey, _##name); \

View File

@@ -50,6 +50,17 @@ namespace Microsoft.Terminal.Settings.Model
AfterCurrentTab,
};
[flags]
enum ConfirmCloseOn
{
Never = 0x0,
Always = 0x1,
MultipleTabs = 0x2,
MultiplePanes = 0x4,
// TODO GH#6549: Future - requires TermControl to expose client count
// MultipleProcesses = 0x8,
};
[default_interface] runtimeclass GlobalAppSettings {
Guid DefaultProfile;
@@ -61,7 +72,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::MultipleTabs | Model::ConfirmCloseOn::MultiplePanes) \
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,38 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Core::MatchMode)
};
};
JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::ConfirmCloseOn)
{
static constexpr std::array<pair_type, 4> mappings = {
pair_type{ "never", AllClear },
pair_type{ "always", ValueType::Always },
pair_type{ "multipleTabs", ValueType::MultipleTabs },
pair_type{ "multiplePanes", ValueType::MultiplePanes },
// TODO GH#6549: Future - requires TermControl to expose client count
// pair_type{ "multipleProcesses", ValueType::MultipleProcesses },
};
auto FromJson(const Json::Value& json)
{
// Support legacy boolean: true -> MultipleTabs|MultiplePanes, false -> Never
if (json.isBool())
{
return json.asBool() ? ValueType::MultipleTabs | ValueType::MultiplePanes : AllClear;
}
return BaseFlagMapper::FromJson(json);
}
bool CanConvert(const Json::Value& json)
{
return BaseFlagMapper::CanConvert(json) || json.isBool();
}
Json::Value ToJson(const ::winrt::Microsoft::Terminal::Settings::Model::ConfirmCloseOn& val)
{
return BaseFlagMapper::ToJson(val);
}
};
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": ["multipleTabs", "multiplePanes"],
"theme": "dark",
"snapToGridOnResize": true,
"disableAnimations": false,

View File

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