diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 15bc6260288..1d387a9e49e 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -304,6 +304,7 @@ "toggleReadOnlyMode", "toggleShaderEffects", "wt", + "quit", "unbound" ], "type": "string" diff --git a/src/cascadia/Remoting/Monarch.cpp b/src/cascadia/Remoting/Monarch.cpp index d6a12c8c39d..9cec5917d85 100644 --- a/src/cascadia/Remoting/Monarch.cpp +++ b/src/cascadia/Remoting/Monarch.cpp @@ -82,6 +82,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation peasant.ShowTrayIconRequested([this](auto&&, auto&&) { _ShowTrayIconRequestedHandlers(*this, nullptr); }); peasant.HideTrayIconRequested([this](auto&&, auto&&) { _HideTrayIconRequestedHandlers(*this, nullptr); }); + peasant.QuitAllRequested({ this, &Monarch::_handleQuitAll }); _peasants[newPeasantsId] = peasant; @@ -109,6 +110,35 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation } } + // Method Description: + // - Gives the host process an opportunity to run any pre-close logic then + // requests all peasants to close. + // Arguments: + // - used + // Return Value: + // - + void Monarch::_handleQuitAll(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*args*/) + { + // Let the process hosting the monarch run any needed logic before + // closing all windows. + _QuitAllRequestedHandlers(*this, nullptr); + + // Tell all peasants to exit. + const auto callback = [&](const auto& /*id*/, const auto& p) { + p.Quit(); + }; + const auto onError = [&](const auto& id) { + TraceLoggingWrite(g_hRemotingProvider, + "Monarch_handleQuitAll_Failed", + TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not close"), + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingKeyword(TIL_KEYWORD_TRACE)); + }; + + _forEachPeasant(callback, onError); + } + // Method Description: // - Tells the monarch that a peasant is being closed. // Arguments: diff --git a/src/cascadia/Remoting/Monarch.h b/src/cascadia/Remoting/Monarch.h index 6be69975eed..ae620af805a 100644 --- a/src/cascadia/Remoting/Monarch.h +++ b/src/cascadia/Remoting/Monarch.h @@ -64,6 +64,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); private: uint64_t _ourPID; @@ -95,6 +96,9 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation void _renameRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args); + void _handleQuitAll(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::Foundation::IInspectable& args); + // Method Description: // - Helper for doing something on each and every peasant. // - We'll try calling func on every peasant. diff --git a/src/cascadia/Remoting/Monarch.idl b/src/cascadia/Remoting/Monarch.idl index eab7eaa92f3..eaf04ad0f3b 100644 --- a/src/cascadia/Remoting/Monarch.idl +++ b/src/cascadia/Remoting/Monarch.idl @@ -58,5 +58,6 @@ namespace Microsoft.Terminal.Remoting event Windows.Foundation.TypedEventHandler HideTrayIconRequested; event Windows.Foundation.TypedEventHandler WindowCreated; event Windows.Foundation.TypedEventHandler WindowClosed; + event Windows.Foundation.TypedEventHandler QuitAllRequested; }; } diff --git a/src/cascadia/Remoting/Peasant.cpp b/src/cascadia/Remoting/Peasant.cpp index a9787f59733..2cb6c5b3fad 100644 --- a/src/cascadia/Remoting/Peasant.cpp +++ b/src/cascadia/Remoting/Peasant.cpp @@ -257,4 +257,36 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), TraceLoggingKeyword(TIL_KEYWORD_TRACE)); } + + void Peasant::RequestQuitAll() + { + try + { + _QuitAllRequestedHandlers(*this, nullptr); + } + catch (...) + { + LOG_CAUGHT_EXCEPTION(); + } + TraceLoggingWrite(g_hRemotingProvider, + "Peasant_RequestQuit", + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingKeyword(TIL_KEYWORD_TRACE)); + } + + void Peasant::Quit() + { + try + { + _QuitRequestedHandlers(*this, nullptr); + } + catch (...) + { + LOG_CAUGHT_EXCEPTION(); + } + TraceLoggingWrite(g_hRemotingProvider, + "Peasant_Quit", + TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), + TraceLoggingKeyword(TIL_KEYWORD_TRACE)); + } } diff --git a/src/cascadia/Remoting/Peasant.h b/src/cascadia/Remoting/Peasant.h index 71c02f737ed..8636d13453a 100644 --- a/src/cascadia/Remoting/Peasant.h +++ b/src/cascadia/Remoting/Peasant.h @@ -30,6 +30,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation void RequestRename(const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args); void RequestShowTrayIcon(); void RequestHideTrayIcon(); + void RequestQuitAll(); + void Quit(); winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs(); @@ -45,6 +47,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior); TYPED_EVENT(ShowTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); private: Peasant(const uint64_t testPID); diff --git a/src/cascadia/Remoting/Peasant.idl b/src/cascadia/Remoting/Peasant.idl index d8efa74002f..75896d733fc 100644 --- a/src/cascadia/Remoting/Peasant.idl +++ b/src/cascadia/Remoting/Peasant.idl @@ -67,6 +67,8 @@ namespace Microsoft.Terminal.Remoting void Summon(SummonWindowBehavior behavior); void RequestShowTrayIcon(); void RequestHideTrayIcon(); + void RequestQuitAll(); + void Quit(); event Windows.Foundation.TypedEventHandler WindowActivated; event Windows.Foundation.TypedEventHandler ExecuteCommandlineRequested; @@ -76,6 +78,8 @@ namespace Microsoft.Terminal.Remoting event Windows.Foundation.TypedEventHandler SummonRequested; event Windows.Foundation.TypedEventHandler ShowTrayIconRequested; event Windows.Foundation.TypedEventHandler HideTrayIconRequested; + event Windows.Foundation.TypedEventHandler QuitAllRequested; + event Windows.Foundation.TypedEventHandler QuitRequested; }; [default_interface] runtimeclass Peasant : IPeasant diff --git a/src/cascadia/Remoting/WindowManager.cpp b/src/cascadia/Remoting/WindowManager.cpp index 668178892b1..5820f650944 100644 --- a/src/cascadia/Remoting/WindowManager.cpp +++ b/src/cascadia/Remoting/WindowManager.cpp @@ -271,6 +271,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation _monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested }); _monarch.ShowTrayIconRequested([this](auto&&, auto&&) { _ShowTrayIconRequestedHandlers(*this, nullptr); }); _monarch.HideTrayIconRequested([this](auto&&, auto&&) { _HideTrayIconRequestedHandlers(*this, nullptr); }); + _monarch.QuitAllRequested([this](auto&&, auto&&) { _QuitAllRequestedHandlers(*this, nullptr); }); _BecameMonarchHandlers(*this, nullptr); } @@ -579,6 +580,19 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation _peasant.RequestHideTrayIcon(); } + // Method Description: + // - Ask the monarch to quit all windows. + // Arguments: + // - + // Return Value: + // - + winrt::fire_and_forget WindowManager::RequestQuitAll() + { + auto strongThis{ get_strong() }; + co_await winrt::resume_background(); + _peasant.RequestQuitAll(); + } + bool WindowManager::DoesQuakeWindowExist() { return _monarch.DoesQuakeWindowExist(); diff --git a/src/cascadia/Remoting/WindowManager.h b/src/cascadia/Remoting/WindowManager.h index 8a4724bfb9f..4136a2cb9a5 100644 --- a/src/cascadia/Remoting/WindowManager.h +++ b/src/cascadia/Remoting/WindowManager.h @@ -47,6 +47,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation winrt::fire_and_forget RequestShowTrayIcon(); winrt::fire_and_forget RequestHideTrayIcon(); + winrt::fire_and_forget RequestQuitAll(); bool DoesQuakeWindowExist(); void UpdateActiveTabTitle(winrt::hstring title); @@ -56,6 +57,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); TYPED_EVENT(ShowTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); private: bool _shouldCreateWindow{ false }; diff --git a/src/cascadia/Remoting/WindowManager.idl b/src/cascadia/Remoting/WindowManager.idl index 7d287146b01..611ebd02ba9 100644 --- a/src/cascadia/Remoting/WindowManager.idl +++ b/src/cascadia/Remoting/WindowManager.idl @@ -17,6 +17,7 @@ namespace Microsoft.Terminal.Remoting void RequestShowTrayIcon(); void RequestHideTrayIcon(); UInt64 GetNumberOfPeasants(); + void RequestQuitAll(); void UpdateActiveTabTitle(String title); Boolean DoesQuakeWindowExist(); Windows.Foundation.Collections.IVectorView GetPeasantInfos(); @@ -26,5 +27,6 @@ namespace Microsoft.Terminal.Remoting event Windows.Foundation.TypedEventHandler WindowClosed; event Windows.Foundation.TypedEventHandler ShowTrayIconRequested; event Windows.Foundation.TypedEventHandler HideTrayIconRequested; + event Windows.Foundation.TypedEventHandler QuitAllRequested; }; } diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 5638c6bb8f8..5bd5e56ed0b 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -78,7 +78,14 @@ namespace winrt::TerminalApp::implementation void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/, const ActionEventArgs& args) { - CloseWindow(); + CloseWindow(false); + args.Handled(true); + } + + void TerminalPage::_HandleQuit(const IInspectable& /*sender*/, + const ActionEventArgs& args) + { + RequestQuit(); args.Handled(true); } diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index 6680fd75bb7..6d53a6ba7ee 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -329,6 +329,14 @@ namespace winrt::TerminalApp::implementation TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance)); } + void AppLogic::Quit() + { + if (_root) + { + _root->CloseWindow(true); + } + } + // Method Description: // - Show a ContentDialog with buttons to take further action. Uses the // FrameworkElements provided as the title and content of this dialog, and @@ -1154,7 +1162,7 @@ namespace winrt::TerminalApp::implementation { if (_root) { - _root->CloseWindow(); + _root->CloseWindow(false); } } diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h index 3cfbd378614..3e9a77bc160 100644 --- a/src/cascadia/TerminalApp/AppLogic.h +++ b/src/cascadia/TerminalApp/AppLogic.h @@ -53,6 +53,8 @@ namespace winrt::TerminalApp::implementation void LoadSettings(); [[nodiscard]] Microsoft::Terminal::Settings::Model::CascadiaSettings GetSettings() const noexcept; + void Quit(); + int32_t SetStartupCommandline(array_view actions); int32_t ExecuteCommandline(array_view actions, const winrt::hstring& cwd); TerminalApp::FindTargetWindowResult FindTargetWindow(array_view actions); @@ -173,6 +175,7 @@ namespace winrt::TerminalApp::implementation FORWARDED_TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs, _root, RenameWindowRequested); FORWARDED_TYPED_EVENT(IsQuakeWindowChanged, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IsQuakeWindowChanged); FORWARDED_TYPED_EVENT(SummonWindowRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, SummonWindowRequested); + FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested); #ifdef UNIT_TESTING friend class TerminalAppLocalTests::CommandlineTest; diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl index 7f0867048a5..9ff673b41ba 100644 --- a/src/cascadia/TerminalApp/AppLogic.idl +++ b/src/cascadia/TerminalApp/AppLogic.idl @@ -39,6 +39,8 @@ namespace TerminalApp String ParseCommandlineMessage { get; }; Boolean ShouldExitEarly { get; }; + void Quit(); + void LoadSettings(); Windows.UI.Xaml.UIElement GetRoot(); @@ -97,5 +99,6 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler SettingsChanged; event Windows.Foundation.TypedEventHandler IsQuakeWindowChanged; event Windows.Foundation.TypedEventHandler SummonWindowRequested; + event Windows.Foundation.TypedEventHandler QuitRequested; } } diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 9f50d6718c2..58d5437a8e3 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -184,6 +184,9 @@ Close all + + Quit + Do you want to close all tabs? @@ -441,6 +444,15 @@ Third-Party Notices A hyperlink name for the Terminal's third-party notices + + Cancel + + + Close all + + + Do you want to close all windows? + Cancel diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index d63684ed9a8..8eda026cdda 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -558,6 +558,21 @@ namespace winrt::TerminalApp::implementation ShellExecute(nullptr, nullptr, currentPath.c_str(), nullptr, nullptr, SW_SHOW); } + // 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. + // - 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 TerminalPage::_ShowQuitDialog() + { + if (auto presenter{ _dialogPresenter.get() }) + { + co_return co_await presenter.ShowDialog(FindName(L"QuitDialog").try_as()); + } + co_return ContentDialogResult::None; + } + // 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 @@ -1237,6 +1252,25 @@ namespace winrt::TerminalApp::implementation } return nullptr; } + // Method Description: + // - Warn the user that they are about to close all open windows, then + // signal that we want to close everything. + fire_and_forget TerminalPage::RequestQuit() + { + if (!_displayingCloseDialog) + { + _displayingCloseDialog = true; + ContentDialogResult warningResult = co_await _ShowQuitDialog(); + _displayingCloseDialog = false; + + if (warningResult != ContentDialogResult::Primary) + { + co_return; + } + + _QuitRequestedHandlers(nullptr, nullptr); + } + } // Method Description: // - Saves the window position and tab layout to the application state @@ -1320,9 +1354,14 @@ namespace winrt::TerminalApp::implementation // Method Description: // - Close the terminal app. If there is more // than one tab opened, show a warning dialog. - fire_and_forget TerminalPage::CloseWindow() + // Arguments: + // - bypassDialog: if true a dialog won't be shown even if the user would + // normally get confirmation. This is used in the case where the user + // has already been prompted by the Quit action. + fire_and_forget TerminalPage::CloseWindow(bool bypassDialog) { - if (_HasMultipleTabs() && + if (!bypassDialog && + _HasMultipleTabs() && _settings.GlobalSettings().ConfirmCloseAllTabs() && !_displayingCloseDialog) { diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 6451e5158a2..772d724ea81 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -71,7 +71,8 @@ namespace winrt::TerminalApp::implementation winrt::hstring ApplicationDisplayName(); winrt::hstring ApplicationVersion(); - winrt::fire_and_forget CloseWindow(); + winrt::fire_and_forget RequestQuit(); + winrt::fire_and_forget CloseWindow(bool bypassDialog); void ToggleFocusMode(); void ToggleFullscreen(); @@ -131,6 +132,7 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs); TYPED_EVENT(IsQuakeWindowChanged, IInspectable, IInspectable); TYPED_EVENT(SummonWindowRequested, IInspectable, IInspectable); + TYPED_EVENT(QuitRequested, IInspectable, IInspectable); private: friend struct TerminalPageT; // for Xaml to bind events @@ -189,6 +191,7 @@ namespace winrt::TerminalApp::implementation std::shared_ptr _windowRenameFailedToast{ nullptr }; void _ShowAboutDialog(); + winrt::Windows::Foundation::IAsyncOperation _ShowQuitDialog(); winrt::Windows::Foundation::IAsyncOperation _ShowCloseWarningDialog(); winrt::Windows::Foundation::IAsyncOperation _ShowCloseReadOnlyDialog(); winrt::Windows::Foundation::IAsyncOperation _ShowMultiLinePasteWarningDialog(); diff --git a/src/cascadia/TerminalApp/TerminalPage.xaml b/src/cascadia/TerminalApp/TerminalPage.xaml index 35ac1807db6..ad592ec77db 100644 --- a/src/cascadia/TerminalApp/TerminalPage.xaml +++ b/src/cascadia/TerminalApp/TerminalPage.xaml @@ -47,6 +47,11 @@ + + Minimize current window to tray + + Quit the Terminal + diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index 9f942d82134..8cf8dd87d4c 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -301,6 +301,7 @@ { "command": "identifyWindow" }, { "command": "openWindowRenamer" }, { "command": "quakeMode", "keys":"win+sc(41)" }, + { "command": "quit" }, // Tab Management // "command": "closeTab" is unbound by default. diff --git a/src/cascadia/UnitTests_Remoting/RemotingTests.cpp b/src/cascadia/UnitTests_Remoting/RemotingTests.cpp index b9b358a8621..5480bc609ee 100644 --- a/src/cascadia/UnitTests_Remoting/RemotingTests.cpp +++ b/src/cascadia/UnitTests_Remoting/RemotingTests.cpp @@ -75,6 +75,8 @@ namespace RemotingUnitTests void Summon(const Remoting::SummonWindowBehavior& /*args*/) { throw winrt::hresult_error{}; }; void RequestShowTrayIcon() { throw winrt::hresult_error{}; }; void RequestHideTrayIcon() { throw winrt::hresult_error{}; }; + void RequestQuitAll() { throw winrt::hresult_error{}; }; + void Quit() { throw winrt::hresult_error{}; }; TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, Remoting::WindowActivatedArgs); TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, Remoting::CommandlineArgs); TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); @@ -83,6 +85,8 @@ namespace RemotingUnitTests TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, Remoting::SummonWindowBehavior); TYPED_EVENT(ShowTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); TYPED_EVENT(HideTrayIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); + TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); }; class RemotingTests diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index 1af50212506..19118df6872 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -213,6 +213,7 @@ void AppHost::_HandleCommandlineArgs() peasant.SummonRequested({ this, &AppHost::_HandleSummon }); peasant.DisplayWindowIdRequested({ this, &AppHost::_DisplayWindowId }); + peasant.QuitRequested({ this, &AppHost::_QuitRequested }); // We need this property to be set before we get the InitialSize/Position // and BecameMonarch which normally sets it is only run after the window @@ -278,6 +279,7 @@ void AppHost::Initialize() _logic.SettingsChanged({ this, &AppHost::_HandleSettingsChanged }); _logic.IsQuakeWindowChanged({ this, &AppHost::_IsQuakeWindowChanged }); _logic.SummonWindowRequested({ this, &AppHost::_SummonWindowRequested }); + _logic.QuitRequested({ this, &AppHost::_RequestQuitAll }); _window->UpdateTitle(_logic.Title()); @@ -690,6 +692,9 @@ void AppHost::_BecomeMonarch(const winrt::Windows::Foundation::IInspectable& /*s // These events are coming from peasants that become or un-become quake windows. _windowManager.ShowTrayIconRequested([this](auto&&, auto&&) { _ShowTrayIconRequested(); }); _windowManager.HideTrayIconRequested([this](auto&&, auto&&) { _HideTrayIconRequested(); }); + // If the monarch receives a QuitAll event it will signal this event to be + // ran before each peasant is closed. + _windowManager.QuitAllRequested({ this, &AppHost::_QuitAllRequested }); } void AppHost::_listenForInboundConnections() @@ -1024,6 +1029,28 @@ void AppHost::_IsQuakeWindowChanged(const winrt::Windows::Foundation::IInspectab _window->IsQuakeWindow(_logic.IsQuakeWindow()); } +winrt::fire_and_forget AppHost::_QuitRequested(const winrt::Windows::Foundation::IInspectable&, + const winrt::Windows::Foundation::IInspectable&) +{ + // Need to be on the main thread to close out all of the tabs. + co_await winrt::resume_foreground(_logic.GetRoot().Dispatcher()); + + _logic.Quit(); +} + +void AppHost::_RequestQuitAll(const winrt::Windows::Foundation::IInspectable&, + const winrt::Windows::Foundation::IInspectable&) +{ + _windowManager.RequestQuitAll(); +} + +void AppHost::_QuitAllRequested(const winrt::Windows::Foundation::IInspectable&, + const winrt::Windows::Foundation::IInspectable&) +{ + // TODO: GH#9800: For now, nothing needs to be done before the monarch closes all windows. + // Later when we have state saving that should go here. +} + void AppHost::_SummonWindowRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable&) { diff --git a/src/cascadia/WindowsTerminal/AppHost.h b/src/cascadia/WindowsTerminal/AppHost.h index ab452353ea7..df804282891 100644 --- a/src/cascadia/WindowsTerminal/AppHost.h +++ b/src/cascadia/WindowsTerminal/AppHost.h @@ -85,6 +85,15 @@ class AppHost void _SummonWindowRequested(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); + winrt::fire_and_forget _QuitRequested(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::Foundation::IInspectable& args); + + void _RequestQuitAll(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::Foundation::IInspectable& args); + + void _QuitAllRequested(const winrt::Windows::Foundation::IInspectable& sender, + const winrt::Windows::Foundation::IInspectable& args); + void _CreateTrayIcon(); void _DestroyTrayIcon(); void _ShowTrayIconRequested();