Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/cascadia/profiles.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@
"toggleReadOnlyMode",
"toggleShaderEffects",
"toggleSplitOrientation",
"workspaces",
"wt",
"unbound"
],
Expand Down Expand Up @@ -2040,6 +2041,11 @@
"unfocusedFrame": {
"description": "The color of the window frame when the window is inactive. This only works on Windows 11",
"$ref": "#/$defs/ThemeColor"
},
"showWindowsButton": {
"description": "When set to true, the workspace/windows button will be shown in the tab row.",
"type": "boolean",
"default": true
}
}
},
Expand Down
53 changes: 53 additions & 0 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,27 @@ namespace winrt::TerminalApp::implementation
co_return;
}

// Launch `wt -w <name>` so the monarch can either summon an existing
// window with that name or restore a persisted workspace.
safe_void_coroutine TerminalPage::_OpenWorkspaceWindow(const winrt::hstring name)
{
co_await winrt::resume_background();

const auto exePath{ GetWtExePath() };
const auto cmdline = fmt::format(FMT_COMPILE(L"-w {}"), std::wstring_view{ name });

SHELLEXECUTEINFOW seInfo{ 0 };
seInfo.cbSize = sizeof(seInfo);
seInfo.fMask = SEE_MASK_NOASYNC;
seInfo.lpVerb = L"open";
seInfo.lpFile = exePath.c_str();
seInfo.lpParameters = cmdline.c_str();
seInfo.nShow = SW_SHOWNORMAL;
LOG_IF_WIN32_BOOL_FALSE(ShellExecuteExW(&seInfo));

co_return;
}

void TerminalPage::_HandleNewWindow(const IInspectable& /*sender*/,
const ActionEventArgs& actionArgs)
{
Expand Down Expand Up @@ -1058,6 +1079,7 @@ namespace winrt::TerminalApp::implementation
// Fun!
// WindowRenamerTextBox().Focus(FocusState::Programmatic);
_renamerLayoutUpdatedRevoker.revoke();
_renamerLayoutCount = 0;
_renamerLayoutUpdatedRevoker = WindowRenamerTextBox().LayoutUpdated(winrt::auto_revoke, [weakThis = get_weak()](auto&&, auto&&) {
if (auto self{ weakThis.get() })
{
Expand Down Expand Up @@ -1633,4 +1655,35 @@ namespace winrt::TerminalApp::implementation
args.Handled(handled);
}
}

void TerminalPage::_HandleOpenWorkspace(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
// Open (or summon) a named window. We launch a new `wt -w <name>`
// process which the monarch will route to the correct live window or
// restore from a persisted workspace.
if (args)
{
if (const auto& realArgs = args.ActionArgs().try_as<OpenWorkspaceArgs>())
{
const auto name = realArgs.Name();
if (!name.empty())
{
_OpenWorkspaceWindow(name);
}
args.Handled(true);
}
}
}

void TerminalPage::_HandleWorkspaces(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (_workspaceFlyout && _workspaceDropdown)
{
_workspaceFlyout.ShowAt(_workspaceDropdown);
}
args.Handled(true);
}

}
4 changes: 4 additions & 0 deletions src/cascadia/TerminalApp/Pane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ INewContentArgs Pane::GetTerminalArgsForPane(BuildStartupKind kind) const
{
// Leaves are the only things that have controls
assert(_IsLeaf());
if (!_content)
{
return nullptr;
}
return _content.GetNewTerminalArgs(kind);
}

Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/Remoting.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ namespace winrt::TerminalApp::implementation
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command, nullptr);
WINRT_PROPERTY(winrt::hstring, Content);
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
WINRT_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::WindowLayout, PersistedLayout, nullptr);
};
}

Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/Remoting.idl
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ namespace TerminalApp
CommandlineArgs Command { get; };
String Content { get; };
Windows.Foundation.IReference<Windows.Foundation.Rect> InitialBounds { get; };
Microsoft.Terminal.Settings.Model.WindowLayout PersistedLayout;
};
}
32 changes: 32 additions & 0 deletions src/cascadia/TerminalApp/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,38 @@
<value>unnamed window</value>
<comment>text used to identify when a window hasn't been assigned a name by the user</comment>
</data>
<data name="NameThisWindowMenuItem" xml:space="preserve">
<value>Name this window…</value>
<comment>Menu item text shown when the current window has no name assigned</comment>
</data>
<data name="RenameThisWindowMenuItem" xml:space="preserve">
<value>Rename this window…</value>
<comment>Menu item text shown when the current window already has a name</comment>
</data>
<data name="WindowListUnnamedEntry" xml:space="preserve">
<value>#{0} (unnamed)</value>
<comment>{0} is the window ID number. Shown in the workspace flyout for windows that have no name assigned.</comment>
</data>
<data name="DeleteWorkspaceMenuItem" xml:space="preserve">
<value>Delete workspace?</value>
<comment>Menu item text shown in the right-click context menu on a saved workspace</comment>
</data>
<data name="OpenWorkspaceMenuItem" xml:space="preserve">
<value>Open workspace</value>
<comment>Menu item text for opening a saved workspace</comment>
</data>
<data name="ConfirmDeleteWorkspaceTitle" xml:space="preserve">
<value>Are you sure you want to delete the workspace "{0}"?</value>
<comment>{0} is the workspace name. Shown in a confirmation dialog when the user tries to delete a saved workspace.</comment>
</data>
<data name="ConfirmDeleteWorkspaceDelete" xml:space="preserve">
<value>Delete</value>
<comment>Primary button text on the delete workspace confirmation dialog</comment>
</data>
<data name="ConfirmDeleteWorkspaceCancel" xml:space="preserve">
<value>Cancel</value>
<comment>Cancel button text on the delete workspace confirmation dialog</comment>
</data>
<data name="WindowRenamer.Subtitle" xml:space="preserve">
<value>Enter a new name:</value>
</data>
Expand Down
44 changes: 44 additions & 0 deletions src/cascadia/TerminalApp/TabManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,21 @@ namespace winrt::TerminalApp::implementation
auto actions = t->BuildStartupActions(BuildStartupKind::None);
_AddPreviouslyClosedPaneOrTab(std::move(actions));

// If this is the last tab in a named window, persist the workspace
// layout now while tab content is still alive. After tab.Close()
// the pane content will be torn down by the time _RemoveTab runs.
if (_tabs.Size() == 1)
{
const auto& windowName = _WindowProperties.WindowName();
if (!windowName.empty())
{
if (const auto layout = GetWindowLayout())
{
ApplicationState::SharedInstance().SaveWorkspace(windowName, layout);
}
}
}

tab.Close();
}

Expand All @@ -471,6 +486,13 @@ namespace winrt::TerminalApp::implementation

const auto focusedTabIndex{ _GetFocusedTabIndex() };

// NOTE: Workspace persistence for named windows used to live here,
// but by the time _RemoveTab runs the pane content may already be
// torn down (e.g. from the close-pane path). Instead, workspace
// saves are handled earlier:
// - Close-pane (last pane): in _HandleClosePaneRequested
// - Close-tab: in _HandleCloseTabRequested

// Removing the tab from the collection should destroy its control and disconnect its connection,
// but it doesn't always do so. The UI tree may still be holding the control and preventing its destruction.
tab.Shutdown();
Expand Down Expand Up @@ -798,6 +820,28 @@ namespace winrt::TerminalApp::implementation
}
_AddPreviouslyClosedPaneOrTab(std::move(state.args));

// If this is the last pane on the last tab of a named window, persist
// the workspace layout now while the pane content is still alive.
// We can't wait until _RemoveTab, because pane->Close() below will
// destroy the content before _RemoveTab is reached.
if (_tabs.Size() == 1)
{
if (const auto activeTab{ _GetFocusedTabImpl() })
{
if (activeTab->GetLeafPaneCount() == 1)
{
const auto& windowName = _WindowProperties.WindowName();
if (!windowName.empty())
{
if (const auto layout = GetWindowLayout())
{
ApplicationState::SharedInstance().SaveWorkspace(windowName, layout);
}
}
}
}
}

// If specified, detach before closing to directly update the pane structure
pane->Close();
}
Expand Down
9 changes: 9 additions & 0 deletions src/cascadia/TerminalApp/TabRowControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ namespace winrt::TerminalApp::implementation
InitializeComponent();
}

void TabRowControl::WorkspaceName(const winrt::hstring& value)
{
if (_WorkspaceName != value)
{
_WorkspaceName = value;
PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"WorkspaceName" });
}
}

// Method Description:
// - Bound in the Xaml editor to the [+] button.
// Arguments:
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/TerminalApp/TabRowControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ namespace winrt::TerminalApp::implementation

til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(bool, ShowElevationShield, PropertyChanged.raise, false);
WINRT_OBSERVABLE_PROPERTY(bool, ShowWindowsButton, PropertyChanged.raise, true);

public:
winrt::hstring WorkspaceName() const noexcept { return _WorkspaceName; }
void WorkspaceName(const winrt::hstring& value);

private:
winrt::hstring _WorkspaceName{};
};
}

Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/TabRowControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ namespace TerminalApp
TabRowControl();
Microsoft.UI.Xaml.Controls.TabView TabView { get; };
Boolean ShowElevationShield;
Boolean ShowWindowsButton;
String WorkspaceName;
}
}
47 changes: 39 additions & 8 deletions src/cascadia/TerminalApp/TabRowControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mtu="using:Microsoft.Terminal.UI"
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
Background="{ThemeResource TabViewBackground}"
mc:Ignorable="d">
Expand Down Expand Up @@ -35,14 +36,44 @@
TabWidthMode="Equal">

<mux:TabView.TabStripHeader>
<!-- EA18 is the "Shield" glyph -->
<FontIcon x:Uid="ElevationShield"
Margin="9,4,0,4"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="16"
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
Glyph="&#xEA18;"
Visibility="{x:Bind ShowElevationShield, Mode=OneWay}" />
<StackPanel Orientation="Horizontal">
<!-- EA18 is the "Shield" glyph -->
<FontIcon x:Uid="ElevationShield"
Margin="9,4,0,4"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="16"
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
Glyph="&#xEA18;"
Visibility="{x:Bind ShowElevationShield, Mode=OneWay}" />

<!-- Workspace/windows button -->
<Button x:Name="WorkspaceDropdown"
Margin="4,0,0,4"
Padding="8,0,0,0"
VerticalAlignment="Stretch"
Background="Transparent"
BorderThickness="0"
Visibility="{x:Bind ShowWindowsButton, Mode=OneWay}">
<Button.Content>
<StackPanel Orientation="Horizontal"
Spacing="8">
<!-- EE40 is the "TaskViewSettings" glyph -->
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="12"
Glyph="&#xEE40;" />
<TextBlock x:Name="WorkspaceNameText"
Padding="0,0,8,0"
VerticalAlignment="Center"
FontSize="12"
Text="{x:Bind WorkspaceName, Mode=OneWay}"
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(WorkspaceName), Mode=OneWay}" />
</StackPanel>
</Button.Content>
<Button.Flyout>
<MenuFlyout x:Name="WorkspaceFlyout" />
</Button.Flyout>
</Button>
</StackPanel>
</mux:TabView.TabStripHeader>

<mux:TabView.TabStripFooter>
Expand Down
Loading
Loading