diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index 2f7a49ef0ab..6657efb67ca 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -703,6 +703,16 @@ namespace winrt::TerminalApp::implementation globals.MinimizeToNotificationArea(); } + bool AppLogic::AllowHeadless() + { + if (!_loadedInitialSettings) + { + // Load settings if we haven't already + ReloadSettings(); + } + return _settings.GlobalSettings().AllowHeadless(); + } + TerminalApp::TerminalWindow AppLogic::CreateNewWindow() { if (_settings == nullptr) diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index f5a206b1826..c3bbf12f5fe 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -67,6 +67,7 @@ namespace winrt::TerminalApp::implementation Microsoft::Terminal::Settings::Model::Theme Theme(); bool IsolatedMode(); + bool AllowHeadless(); bool RequestsTrayIcon(); TerminalApp::TerminalWindow CreateNewWindow(); diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index 5eac395390f..cb5c920bbee 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -46,6 +46,7 @@ namespace TerminalApp // Selected settings to expose Microsoft.Terminal.Settings.Model.Theme Theme { get; }; Boolean IsolatedMode { get; }; + Boolean AllowHeadless { get; }; Boolean RequestsTrayIcon { get; }; FindTargetWindowResult FindTargetWindow(String[] args); diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl index 5a32d3eebf0..a9745cf7804 100644 --- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl +++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.idl @@ -99,6 +99,7 @@ namespace Microsoft.Terminal.Settings.Model INHERITABLE_SETTING(IVector, NewTabMenu); INHERITABLE_SETTING(Boolean, EnableColorSelection); INHERITABLE_SETTING(Boolean, IsolatedMode); + INHERITABLE_SETTING(Boolean, AllowHeadless); Windows.Foundation.Collections.IMapView ColorSchemes(); void AddColorScheme(ColorScheme scheme); diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h index 798505de23d..84a6002d0ee 100644 --- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h +++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h @@ -64,6 +64,7 @@ Author(s): X(bool, TrimPaste, "trimPaste", true) \ X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \ X(winrt::Windows::Foundation::Collections::IVector, NewTabMenu, "newTabMenu", winrt::single_threaded_vector({ Model::RemainingProfilesEntry{} })) \ + X(bool, AllowHeadless, "compatibility.allowHeadless", false) \ X(bool, IsolatedMode, "compatibility.isolatedMode", false) #define MTSM_PROFILE_SETTINGS(X) \ diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.cpp b/src/cascadia/WindowsTerminal/WindowEmperor.cpp index 3343004aa0b..52b688485ce 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.cpp +++ b/src/cascadia/WindowsTerminal/WindowEmperor.cpp @@ -202,7 +202,13 @@ void WindowEmperor::_windowExitedHandler(uint64_t senderID) return w->Peasant().GetID() == senderID; }); - if (_windowThreadInstances.fetch_sub(1, std::memory_order_relaxed) == 1) + // When we run out of windows, exit our process if and only if: + // * We're not allowed to run headless OR + // * we've explicitly been told to "quit", which should fully exit the Terminal. + const bool quitWhenLastWindowExits{ !_app.Logic().AllowHeadless() }; + const bool noMoreWindows{ _windowThreadInstances.fetch_sub(1, std::memory_order_relaxed) == 1 }; + if (noMoreWindows && + (_quitting || quitWhenLastWindowExits)) { _close(); } @@ -297,6 +303,8 @@ void WindowEmperor::_numberOfWindowsChanged(const winrt::Windows::Foundation::II void WindowEmperor::_quitAllRequested(const winrt::Windows::Foundation::IInspectable&, const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& args) { + _quitting = true; + // Make sure that the current timer is destroyed so that it doesn't attempt // to run while we are in the middle of quitting. if (_getWindowLayoutThrottler.has_value()) diff --git a/src/cascadia/WindowsTerminal/WindowEmperor.h b/src/cascadia/WindowsTerminal/WindowEmperor.h index 73e3f1ebbe1..200546c21ba 100644 --- a/src/cascadia/WindowsTerminal/WindowEmperor.h +++ b/src/cascadia/WindowsTerminal/WindowEmperor.h @@ -52,6 +52,8 @@ class WindowEmperor : public std::enable_shared_from_this std::unique_ptr _notificationIcon; + bool _quitting{ false }; + void _windowStartedHandlerPostXAML(const std::shared_ptr& sender); void _windowExitedHandler(uint64_t senderID);