mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Persist window layout every few minutes (#18898)
If `persistedWindowLayout` is enabled, we now persist the window layout every few minutes (excluding the text buffer). This was done by adding a `SafeDispatcherTimer` to the `WindowEmperor` that calls `PersistState()` every 5 minutes. For `BuildStartupKind`, I split up `Persist` into `PersistAll` and `PersistLayout`. This way, we go through all the same code flow that `Persist` had except for specifically serializing the buffer. ## Validation Steps Performed ✅ (with the timer set to 3 seconds) create a window layout and ensure the layout is restored after forcefully stopping Terminal (aka simulating a "crash") Closes #18838
This commit is contained in:
parent
9e0ca3aac0
commit
f769597d89
@ -8,7 +8,8 @@ namespace TerminalApp
|
|||||||
None,
|
None,
|
||||||
Content,
|
Content,
|
||||||
MovePane,
|
MovePane,
|
||||||
Persist,
|
PersistLayout,
|
||||||
|
PersistAll
|
||||||
};
|
};
|
||||||
|
|
||||||
runtimeclass BellEventArgs
|
runtimeclass BellEventArgs
|
||||||
|
|||||||
@ -1953,7 +1953,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalPage::PersistState()
|
void TerminalPage::PersistState(bool serializeBuffer)
|
||||||
{
|
{
|
||||||
// This method may be called for a window even if it hasn't had a tab yet or lost all of them.
|
// This method may be called for a window even if it hasn't had a tab yet or lost all of them.
|
||||||
// We shouldn't persist such windows.
|
// We shouldn't persist such windows.
|
||||||
@ -1968,7 +1968,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
for (auto tab : _tabs)
|
for (auto tab : _tabs)
|
||||||
{
|
{
|
||||||
auto t = winrt::get_self<implementation::TabBase>(tab);
|
auto t = winrt::get_self<implementation::TabBase>(tab);
|
||||||
auto tabActions = t->BuildStartupActions(BuildStartupKind::Persist);
|
auto tabActions = t->BuildStartupActions(serializeBuffer ? BuildStartupKind::PersistAll : BuildStartupKind::PersistLayout);
|
||||||
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
|
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -113,7 +113,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
|
|
||||||
safe_void_coroutine RequestQuit();
|
safe_void_coroutine RequestQuit();
|
||||||
safe_void_coroutine CloseWindow();
|
safe_void_coroutine CloseWindow();
|
||||||
void PersistState();
|
void PersistState(bool serializeBuffer);
|
||||||
|
|
||||||
void ToggleFocusMode();
|
void ToggleFocusMode();
|
||||||
void ToggleFullscreen();
|
void ToggleFullscreen();
|
||||||
|
|||||||
@ -141,7 +141,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
// "attach existing" rather than a "create"
|
// "attach existing" rather than a "create"
|
||||||
args.ContentId(_control.ContentId());
|
args.ContentId(_control.ContentId());
|
||||||
break;
|
break;
|
||||||
case BuildStartupKind::Persist:
|
case BuildStartupKind::PersistAll:
|
||||||
{
|
{
|
||||||
const auto connection = _control.Connection();
|
const auto connection = _control.Connection();
|
||||||
const auto id = connection ? connection.SessionId() : winrt::guid{};
|
const auto id = connection ? connection.SessionId() : winrt::guid{};
|
||||||
@ -156,6 +156,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case BuildStartupKind::PersistLayout:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -266,11 +266,11 @@ namespace winrt::TerminalApp::implementation
|
|||||||
AppLogic::Current()->NotifyRootInitialized();
|
AppLogic::Current()->NotifyRootInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWindow::PersistState()
|
void TerminalWindow::PersistState(bool serializeBuffer)
|
||||||
{
|
{
|
||||||
if (_root)
|
if (_root)
|
||||||
{
|
{
|
||||||
_root->PersistState();
|
_root->PersistState(serializeBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -71,7 +71,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
|
|
||||||
void Create();
|
void Create();
|
||||||
|
|
||||||
void PersistState();
|
void PersistState(bool serializeBuffer);
|
||||||
|
|
||||||
void UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args);
|
void UpdateSettings(winrt::TerminalApp::SettingsLoadEventArgs args);
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,7 @@ namespace TerminalApp
|
|||||||
Boolean ShouldImmediatelyHandoffToElevated();
|
Boolean ShouldImmediatelyHandoffToElevated();
|
||||||
void HandoffToElevated();
|
void HandoffToElevated();
|
||||||
|
|
||||||
void PersistState();
|
void PersistState(Boolean serializeBuffer);
|
||||||
|
|
||||||
Windows.UI.Xaml.UIElement GetRoot();
|
Windows.UI.Xaml.UIElement GetRoot();
|
||||||
|
|
||||||
|
|||||||
@ -314,6 +314,7 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
|||||||
_createMessageWindow(windowClassName.c_str());
|
_createMessageWindow(windowClassName.c_str());
|
||||||
_setupGlobalHotkeys();
|
_setupGlobalHotkeys();
|
||||||
_checkWindowsForNotificationIcon();
|
_checkWindowsForNotificationIcon();
|
||||||
|
_setupSessionPersistence(_app.Logic().Settings().GlobalSettings().ShouldUsePersistedLayout());
|
||||||
|
|
||||||
// When the settings change, we'll want to update our global hotkeys
|
// When the settings change, we'll want to update our global hotkeys
|
||||||
// and our notification icon based on the new settings.
|
// and our notification icon based on the new settings.
|
||||||
@ -323,6 +324,7 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
|||||||
_assertIsMainThread();
|
_assertIsMainThread();
|
||||||
_setupGlobalHotkeys();
|
_setupGlobalHotkeys();
|
||||||
_checkWindowsForNotificationIcon();
|
_checkWindowsForNotificationIcon();
|
||||||
|
_setupSessionPersistence(args.NewSettings().GlobalSettings().ShouldUsePersistedLayout());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -921,10 +923,22 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
|
|||||||
return DefWindowProcW(window, message, wParam, lParam);
|
return DefWindowProcW(window, message, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowEmperor::_finalizeSessionPersistence() const
|
void WindowEmperor::_setupSessionPersistence(bool enabled)
|
||||||
{
|
{
|
||||||
const auto state = ApplicationState::SharedInstance();
|
if (!enabled)
|
||||||
|
{
|
||||||
|
_persistStateTimer.Stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_persistStateTimer.Interval(std::chrono::minutes(5));
|
||||||
|
_persistStateTimer.Tick([&](auto&&, auto&&) {
|
||||||
|
_persistState(ApplicationState::SharedInstance(), false);
|
||||||
|
});
|
||||||
|
_persistStateTimer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowEmperor::_persistState(const ApplicationState& state, bool serializeBuffer) const
|
||||||
|
{
|
||||||
// Calling an `ApplicationState` setter triggers a write to state.json.
|
// Calling an `ApplicationState` setter triggers a write to state.json.
|
||||||
// With this if condition we avoid an unnecessary write when persistence is disabled.
|
// With this if condition we avoid an unnecessary write when persistence is disabled.
|
||||||
if (state.PersistedWindowLayouts())
|
if (state.PersistedWindowLayouts())
|
||||||
@ -936,12 +950,19 @@ void WindowEmperor::_finalizeSessionPersistence() const
|
|||||||
{
|
{
|
||||||
for (const auto& w : _windows)
|
for (const auto& w : _windows)
|
||||||
{
|
{
|
||||||
w->Logic().PersistState();
|
w->Logic().PersistState(serializeBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure to write the state.json before we TerminateProcess()
|
// Ensure to write the state.json
|
||||||
state.Flush();
|
state.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowEmperor::_finalizeSessionPersistence() const
|
||||||
|
{
|
||||||
|
const auto state = ApplicationState::SharedInstance();
|
||||||
|
|
||||||
|
_persistState(state, true);
|
||||||
|
|
||||||
if (_needsPersistenceCleanup)
|
if (_needsPersistenceCleanup)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -64,6 +64,8 @@ private:
|
|||||||
void _registerHotKey(int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept;
|
void _registerHotKey(int index, const winrt::Microsoft::Terminal::Control::KeyChord& hotkey) noexcept;
|
||||||
void _unregisterHotKey(int index) noexcept;
|
void _unregisterHotKey(int index) noexcept;
|
||||||
void _setupGlobalHotkeys();
|
void _setupGlobalHotkeys();
|
||||||
|
void _setupSessionPersistence(bool enabled);
|
||||||
|
void _persistState(const winrt::Microsoft::Terminal::Settings::Model::ApplicationState& state, bool serializeBuffer) const;
|
||||||
void _finalizeSessionPersistence() const;
|
void _finalizeSessionPersistence() const;
|
||||||
void _checkWindowsForNotificationIcon();
|
void _checkWindowsForNotificationIcon();
|
||||||
|
|
||||||
@ -77,6 +79,7 @@ private:
|
|||||||
bool _notificationIconShown = false;
|
bool _notificationIconShown = false;
|
||||||
bool _forcePersistence = false;
|
bool _forcePersistence = false;
|
||||||
bool _needsPersistenceCleanup = false;
|
bool _needsPersistenceCleanup = false;
|
||||||
|
SafeDispatcherTimer _persistStateTimer;
|
||||||
std::optional<bool> _currentSystemThemeIsDark;
|
std::optional<bool> _currentSystemThemeIsDark;
|
||||||
int32_t _windowCount = 0;
|
int32_t _windowCount = 0;
|
||||||
int32_t _messageBoxCount = 0;
|
int32_t _messageBoxCount = 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user