Add support for running the Terminal without _any_ windows (#14944)

This adds a setting (`compatibility.allowHeadless`) to let the Terminal
keep running even when all windows are closed. This lets hotkeys keep
working, because the Emperor thread is still running, just, without any
windows.

I'm really tempted to invoke the magic "closes" word on #9996, but
honestly, we should also add some sort of support for `wt --headless` or
`wt --hidden` or whatever, before we close that. There's also #13630
which seems imminently doable.

Tested manually. I'd post a gif of "close all terminal windows, then
invoke the quakeMode binding and \*presto\*, but that would be an
unnecessarily big gif.

Related to #9996 but not enough to close it if you ask me
This commit is contained in:
Mike Griese
2023-04-06 12:39:40 -05:00
committed by GitHub
parent fe66ba5f58
commit 6f8ef58673
7 changed files with 25 additions and 1 deletions

View File

@@ -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)

View File

@@ -67,6 +67,7 @@ namespace winrt::TerminalApp::implementation
Microsoft::Terminal::Settings::Model::Theme Theme();
bool IsolatedMode();
bool AllowHeadless();
bool RequestsTrayIcon();
TerminalApp::TerminalWindow CreateNewWindow();

View File

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

View File

@@ -99,6 +99,7 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_SETTING(IVector<NewTabMenuEntry>, NewTabMenu);
INHERITABLE_SETTING(Boolean, EnableColorSelection);
INHERITABLE_SETTING(Boolean, IsolatedMode);
INHERITABLE_SETTING(Boolean, AllowHeadless);
Windows.Foundation.Collections.IMapView<String, ColorScheme> ColorSchemes();
void AddColorScheme(ColorScheme scheme);

View File

@@ -64,6 +64,7 @@ Author(s):
X(bool, TrimPaste, "trimPaste", true) \
X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \
X(winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry>, NewTabMenu, "newTabMenu", winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} })) \
X(bool, AllowHeadless, "compatibility.allowHeadless", false) \
X(bool, IsolatedMode, "compatibility.isolatedMode", false)
#define MTSM_PROFILE_SETTINGS(X) \

View File

@@ -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())

View File

@@ -52,6 +52,8 @@ private:
std::unique_ptr<NotificationIcon> _notificationIcon;
bool _quitting{ false };
void _windowStartedHandlerPostXAML(const std::shared_ptr<WindowThread>& sender);
void _windowExitedHandler(uint64_t senderID);