mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-19 03:10:49 +00:00
Compare commits
20 Commits
niels9001/
...
v1.23.1073
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38783fa595 | ||
|
|
a0140ef644 | ||
|
|
490e2bfc06 | ||
|
|
c1cd6d3d1d | ||
|
|
d938f924bb | ||
|
|
e9520c02ea | ||
|
|
2060fd6b11 | ||
|
|
70996f35d0 | ||
|
|
a37dc26fd8 | ||
|
|
29e401f202 | ||
|
|
0d7e1293fa | ||
|
|
a72531014c | ||
|
|
2590ff1383 | ||
|
|
863cdd44f2 | ||
|
|
73721c7a90 | ||
|
|
deeba28fda | ||
|
|
b43e7b93ec | ||
|
|
c6e20e99d7 | ||
|
|
8b0fc20f83 | ||
|
|
77638840e4 |
@@ -287,7 +287,7 @@ namespace TerminalAppLocalTests
|
||||
NewTabArgs args{ newTerminalArgs };
|
||||
ActionAndArgs newTabAction{ ShortcutAction::NewTab, args };
|
||||
// push the arg onto the front
|
||||
page->_startupActions.Append(newTabAction);
|
||||
page->_startupActions.push_back(std::move(newTabAction));
|
||||
Log::Comment(L"Added a single newTab action");
|
||||
|
||||
auto app = ::winrt::Windows::UI::Xaml::Application::Current();
|
||||
|
||||
@@ -752,13 +752,11 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto& realArgs = actionArgs.ActionArgs().try_as<ExecuteCommandlineArgs>())
|
||||
{
|
||||
auto actions = winrt::single_threaded_vector<ActionAndArgs>(
|
||||
TerminalPage::ConvertExecuteCommandlineToActions(realArgs));
|
||||
|
||||
if (actions.Size() != 0)
|
||||
auto actions = ConvertExecuteCommandlineToActions(realArgs);
|
||||
if (!actions.empty())
|
||||
{
|
||||
actionArgs.Handled(true);
|
||||
ProcessStartupActions(actions, false);
|
||||
ProcessStartupActions(std::move(actions), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,8 +184,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// this as a MTA, before the app is Create()'d
|
||||
WINRT_ASSERT(_loadedInitialSettings);
|
||||
|
||||
_ApplyLanguageSettingChange();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"AppCreated",
|
||||
@@ -435,6 +433,10 @@ namespace winrt::TerminalApp::implementation
|
||||
_settings.LogSettingChanges(true);
|
||||
}
|
||||
|
||||
_ApplyLanguageSettingChange();
|
||||
_ApplyStartupTaskStateChange();
|
||||
_ProcessLazySettingsChanges();
|
||||
|
||||
if (initialLoad)
|
||||
{
|
||||
// Register for directory change notification.
|
||||
@@ -445,10 +447,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// Here, we successfully reloaded the settings, and created a new
|
||||
// TerminalSettings object.
|
||||
|
||||
_ApplyLanguageSettingChange();
|
||||
_ApplyStartupTaskStateChange();
|
||||
_ProcessLazySettingsChanges();
|
||||
|
||||
auto warnings{ winrt::multi_threaded_vector<SettingsLoadWarnings>() };
|
||||
for (auto&& warn : _warnings)
|
||||
{
|
||||
|
||||
@@ -359,7 +359,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_switchToMode(CommandPaletteMode::CommandlineMode);
|
||||
e.Handled(true);
|
||||
}
|
||||
else if (key == VirtualKey::C && ctrlDown)
|
||||
else if ((key == VirtualKey::C || key == VirtualKey::Insert) && ctrlDown)
|
||||
{
|
||||
_searchBox().CopySelectionToClipboard();
|
||||
e.Handled(true);
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
<value>ウィンドウを閉じる</value>
|
||||
</data>
|
||||
<data name="SplitTabText" xml:space="preserve">
|
||||
<value>[分割] タブ</value>
|
||||
<value>タブを分割</value>
|
||||
</data>
|
||||
<data name="SplitPaneText" xml:space="preserve">
|
||||
<value>ウィンドウを分割する</value>
|
||||
@@ -224,7 +224,7 @@
|
||||
<value>リセット</value>
|
||||
</data>
|
||||
<data name="RenameTabText" xml:space="preserve">
|
||||
<value>[名前の変更] タブ</value>
|
||||
<value>タブ名を変更</value>
|
||||
</data>
|
||||
<data name="DuplicateTabText" xml:space="preserve">
|
||||
<value>タブを複製する</value>
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
// NOTE: `TerminalPage::_HandleCloseTabRequested` relies on the content being null after this call.
|
||||
Content(nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +158,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// Set this tab's icon to the icon from the content
|
||||
_UpdateTabIcon(*newTabImpl);
|
||||
|
||||
// This is necessary, because WinUI does not have support for middle clicks.
|
||||
// Its Tapped event doesn't provide the information what button was used either.
|
||||
tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabPointerPressed });
|
||||
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabPointerReleased });
|
||||
tabViewItem.PointerExited({ this, &TerminalPage::_OnTabPointerExited });
|
||||
@@ -903,19 +905,39 @@ namespace winrt::TerminalApp::implementation
|
||||
if (_tabPointerMiddleButtonPressed && !eventArgs.GetCurrentPoint(nullptr).Properties().IsMiddleButtonPressed())
|
||||
{
|
||||
_tabPointerMiddleButtonPressed = false;
|
||||
if (const auto tabViewItem{ sender.try_as<MUX::Controls::TabViewItem>() })
|
||||
if (auto tabViewItem{ sender.try_as<MUX::Controls::TabViewItem>() })
|
||||
{
|
||||
tabViewItem.ReleasePointerCapture(eventArgs.Pointer());
|
||||
auto tab = _GetTabByTabViewItem(tabViewItem);
|
||||
if (!_tabPointerMiddleButtonExited && tab)
|
||||
if (!_tabPointerMiddleButtonExited)
|
||||
{
|
||||
_HandleCloseTabRequested(tab);
|
||||
_OnTabPointerReleasedCloseTab(std::move(tabViewItem));
|
||||
}
|
||||
}
|
||||
eventArgs.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
safe_void_coroutine TerminalPage::_OnTabPointerReleasedCloseTab(winrt::Microsoft::UI::Xaml::Controls::TabViewItem sender)
|
||||
{
|
||||
const auto tab = _GetTabByTabViewItem(sender);
|
||||
if (!tab)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// WinUI asynchronously updates its tab view items, so it may happen that we're given a
|
||||
// `TabViewItem` that still contains a `TabBase` which has actually already been removed.
|
||||
// First we must yield once, to flush out whatever TabView is currently doing.
|
||||
const auto strong = get_strong();
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
|
||||
// `tab.Shutdown()` in `_RemoveTab()` sets the content to null = This checks if the tab is closed.
|
||||
if (tab.Content())
|
||||
{
|
||||
_HandleCloseTabRequested(tab);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Tracking pointer state for tab remove
|
||||
// Arguments:
|
||||
|
||||
@@ -51,8 +51,10 @@ namespace winrt::TerminalApp::implementation
|
||||
_tabStatusChangedRevoker = status.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& /*e*/) {
|
||||
// Sometimes nested bindings do not get updated,
|
||||
// thus let's notify property changed on TabStatus when one of its properties changes
|
||||
auto item{ weakThis.get() };
|
||||
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
|
||||
if (auto item{ weakThis.get() })
|
||||
{
|
||||
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalPage::TerminalPage(TerminalApp::WindowProperties properties, const TerminalApp::ContentManager& manager) :
|
||||
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
|
||||
_mruTabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
|
||||
_startupActions{ winrt::single_threaded_vector<ActionAndArgs>() },
|
||||
_manager{ manager },
|
||||
_hostingHwnd{},
|
||||
_WindowProperties{ std::move(properties) }
|
||||
@@ -297,7 +296,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// GH#12267: Don't forget about defterm handoff here. If we're being
|
||||
// created for embedding, then _yea_, we don't need to handoff to an
|
||||
// elevated window.
|
||||
if (!_startupActions || IsRunningElevated() || _shouldStartInboundListener || _startupActions.Size() == 0)
|
||||
if (_startupActions.empty() || IsRunningElevated() || _shouldStartInboundListener)
|
||||
{
|
||||
// there aren't startup actions, or we're elevated. In that case, go for it.
|
||||
return false;
|
||||
@@ -375,7 +374,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void TerminalPage::HandoffToElevated(const CascadiaSettings& settings)
|
||||
{
|
||||
if (!_startupActions)
|
||||
if (_startupActions.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -489,7 +488,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_startupState = StartupState::InStartup;
|
||||
|
||||
ProcessStartupActions(_startupActions, true);
|
||||
ProcessStartupActions(std::move(_startupActions), true);
|
||||
|
||||
// If we were told that the COM server needs to be started to listen for incoming
|
||||
// default application connections, start it now.
|
||||
@@ -546,80 +545,56 @@ namespace winrt::TerminalApp::implementation
|
||||
// nt -d .` from inside another directory to work as expected.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
safe_void_coroutine TerminalPage::ProcessStartupActions(Windows::Foundation::Collections::IVector<ActionAndArgs> actions,
|
||||
const bool initial,
|
||||
const winrt::hstring cwd,
|
||||
const winrt::hstring env)
|
||||
safe_void_coroutine TerminalPage::ProcessStartupActions(std::vector<ActionAndArgs> actions, const bool initial, const winrt::hstring cwd, const winrt::hstring env)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
// Handle it on a subsequent pass of the UI thread.
|
||||
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
|
||||
const auto strong = get_strong();
|
||||
|
||||
// If the caller provided a CWD, "switch" to that directory, then switch
|
||||
// back once we're done. This looks weird though, because we have to set
|
||||
// up the scope_exit _first_. We'll release the scope_exit if we don't
|
||||
// actually need it.
|
||||
|
||||
// back once we're done.
|
||||
auto originalVirtualCwd{ _WindowProperties.VirtualWorkingDirectory() };
|
||||
auto restoreCwd = wil::scope_exit([&originalVirtualCwd, this]() {
|
||||
// ignore errors, we'll just power on through. We'd rather do
|
||||
// something rather than fail silently if the directory doesn't
|
||||
// actually exist.
|
||||
_WindowProperties.VirtualWorkingDirectory(originalVirtualCwd);
|
||||
});
|
||||
|
||||
// Literally the same thing with env vars too
|
||||
auto originalVirtualEnv{ _WindowProperties.VirtualEnvVars() };
|
||||
auto restoreEnv = wil::scope_exit([&originalVirtualEnv, this]() {
|
||||
_WindowProperties.VirtualEnvVars(originalVirtualEnv);
|
||||
auto restoreCwd = wil::scope_exit([&]() {
|
||||
if (!cwd.empty())
|
||||
{
|
||||
// ignore errors, we'll just power on through. We'd rather do
|
||||
// something rather than fail silently if the directory doesn't
|
||||
// actually exist.
|
||||
_WindowProperties.VirtualWorkingDirectory(originalVirtualCwd);
|
||||
_WindowProperties.VirtualEnvVars(originalVirtualEnv);
|
||||
}
|
||||
});
|
||||
_WindowProperties.VirtualWorkingDirectory(cwd);
|
||||
_WindowProperties.VirtualEnvVars(env);
|
||||
|
||||
if (cwd.empty())
|
||||
for (size_t i = 0; i < actions.size(); ++i)
|
||||
{
|
||||
// We didn't actually need to change the virtual CWD, so we don't
|
||||
// need to restore it
|
||||
restoreCwd.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
_WindowProperties.VirtualWorkingDirectory(cwd);
|
||||
}
|
||||
|
||||
if (env.empty())
|
||||
{
|
||||
restoreEnv.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
_WindowProperties.VirtualEnvVars(env);
|
||||
}
|
||||
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
for (const auto& action : actions)
|
||||
if (i != 0)
|
||||
{
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
_actionDispatch->DoAction(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
// Each action may rely on the XAML layout of a preceding action.
|
||||
// Most importantly, this is the case for the combination of NewTab + SplitPane,
|
||||
// as the former appears to only have a layout size after at least 1 resume_foreground,
|
||||
// while the latter relies on that information. This is also why it uses Low priority.
|
||||
//
|
||||
// Curiously, this does not seem to be required when using startupActions, but only when
|
||||
// tearing out a tab (this currently creates a new window with injected startup actions).
|
||||
// This indicates that this is really more of an architectural issue and not a fundamental one.
|
||||
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::Low);
|
||||
}
|
||||
|
||||
// GH#6586: now that we're done processing all startup commands,
|
||||
// focus the active control. This will work as expected for both
|
||||
// commandline invocations and for `wt` action invocations.
|
||||
if (const auto& terminalTab{ _GetFocusedTabImpl() })
|
||||
_actionDispatch->DoAction(actions[i]);
|
||||
}
|
||||
|
||||
// GH#6586: now that we're done processing all startup commands,
|
||||
// focus the active control. This will work as expected for both
|
||||
// commandline invocations and for `wt` action invocations.
|
||||
if (const auto& terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (const auto& content{ terminalTab->GetActiveContent() })
|
||||
{
|
||||
if (const auto& content{ terminalTab->GetActiveContent() })
|
||||
{
|
||||
content.Focus(FocusState::Programmatic);
|
||||
}
|
||||
content.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
|
||||
if (initial)
|
||||
{
|
||||
_CompleteInitialization();
|
||||
@@ -1783,16 +1758,22 @@ namespace winrt::TerminalApp::implementation
|
||||
auto tab{ weakTab.get() };
|
||||
if (page && tab)
|
||||
{
|
||||
if (args.PropertyName() == L"Title")
|
||||
const auto propertyName = args.PropertyName();
|
||||
if (propertyName == L"Title")
|
||||
{
|
||||
page->_UpdateTitle(*tab);
|
||||
}
|
||||
else if (args.PropertyName() == L"Content")
|
||||
else if (propertyName == L"Content")
|
||||
{
|
||||
if (*tab == page->_GetFocusedTab())
|
||||
{
|
||||
page->_tabContent.Children().Clear();
|
||||
page->_tabContent.Children().Append(tab->Content());
|
||||
const auto children = page->_tabContent.Children();
|
||||
|
||||
children.Clear();
|
||||
if (auto content = tab->Content())
|
||||
{
|
||||
page->_tabContent.Children().Append(std::move(content));
|
||||
}
|
||||
|
||||
tab->Focus(FocusState::Programmatic);
|
||||
}
|
||||
@@ -1988,6 +1969,12 @@ namespace winrt::TerminalApp::implementation
|
||||
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
|
||||
}
|
||||
|
||||
// Avoid persisting a window with zero tabs, because `BuildStartupActions` happened to return an empty vector.
|
||||
if (actions.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if the focused tab was not the last tab, restore that
|
||||
auto idx = _GetFocusedTabIndex();
|
||||
if (idx && idx != tabCount - 1)
|
||||
@@ -3658,13 +3645,9 @@ namespace winrt::TerminalApp::implementation
|
||||
// - actions: a list of Actions to process on startup.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::SetStartupActions(std::vector<ActionAndArgs>& actions)
|
||||
void TerminalPage::SetStartupActions(std::vector<ActionAndArgs> actions)
|
||||
{
|
||||
// The fastest way to copy all the actions out of the std::vector and
|
||||
// put them into a winrt::IVector is by making a copy, then moving the
|
||||
// copy into the winrt vector ctor.
|
||||
auto listCopy = actions;
|
||||
_startupActions = winrt::single_threaded_vector<ActionAndArgs>(std::move(listCopy));
|
||||
_startupActions = std::move(actions);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void Maximized(bool newMaximized);
|
||||
void RequestSetMaximized(bool newMaximized);
|
||||
|
||||
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
|
||||
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions);
|
||||
|
||||
void SetInboundListener(bool isEmbedding);
|
||||
static std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> ConvertExecuteCommandlineToActions(const Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
|
||||
@@ -146,7 +146,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void ActionSaveFailed(winrt::hstring message);
|
||||
void ShowTerminalWorkingDirectory();
|
||||
|
||||
safe_void_coroutine ProcessStartupActions(Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
|
||||
safe_void_coroutine ProcessStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> actions,
|
||||
const bool initial,
|
||||
const winrt::hstring cwd = winrt::hstring{},
|
||||
const winrt::hstring env = winrt::hstring{});
|
||||
@@ -255,7 +255,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::Windows::UI::Xaml::Controls::Grid::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
StartupState _startupState{ StartupState::NotInitialized };
|
||||
|
||||
Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||
bool _shouldStartInboundListener{ false };
|
||||
bool _isEmbeddingInboundListener{ false };
|
||||
|
||||
@@ -433,6 +433,7 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _tabPointerMiddleButtonExited{ false };
|
||||
void _OnTabPointerPressed(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
void _OnTabPointerReleased(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
safe_void_coroutine _OnTabPointerReleasedCloseTab(winrt::Microsoft::UI::Xaml::Controls::TabViewItem sender);
|
||||
void _OnTabPointerEntered(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
void _OnTabPointerExited(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs);
|
||||
|
||||
|
||||
@@ -851,6 +851,9 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
// Don't forget to call the overridden function. :)
|
||||
TabBase::Shutdown();
|
||||
|
||||
if (_rootPane)
|
||||
{
|
||||
_rootPane->Shutdown();
|
||||
|
||||
@@ -144,7 +144,6 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Now that we know we can do XAML, build our page.
|
||||
_root = winrt::make_self<TerminalPage>(*_WindowProperties, _manager);
|
||||
_dialog = ContentDialog{};
|
||||
|
||||
// Pass in information about the initial state of the window.
|
||||
// * If we were supposed to start from serialized "content", do that,
|
||||
@@ -313,6 +312,15 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
return _settings.GlobalSettings().CurrentTheme();
|
||||
}
|
||||
|
||||
// WinUI can't show 2 dialogs simultaneously. Yes, really. If you do, you get an exception.
|
||||
// As such, we must dismiss whatever dialog is currently being shown.
|
||||
//
|
||||
// This limit is of course per-thread and not per-window. Yes... really. See:
|
||||
// https://github.com/microsoft/microsoft-ui-xaml/issues/794
|
||||
// The consequence is that we use a static variable to keep track of the shown dialog.
|
||||
static ContentDialog s_activeDialog{ nullptr };
|
||||
|
||||
// Method Description:
|
||||
// - Show a ContentDialog with buttons to take further action. Uses the
|
||||
// FrameworkElements provided as the title and content of this dialog, and
|
||||
@@ -328,16 +336,32 @@ namespace winrt::TerminalApp::implementation
|
||||
// - an IAsyncOperation with the dialog result
|
||||
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalWindow::ShowDialog(winrt::WUX::Controls::ContentDialog dialog)
|
||||
{
|
||||
// DON'T release this lock in a wil::scope_exit. The scope_exit will get
|
||||
// called when we await, which is not what we want.
|
||||
std::unique_lock lock{ _dialogLock, std::try_to_lock };
|
||||
if (!lock)
|
||||
// As mentioned on s_activeDialog, dismissing the active dialog is necessary.
|
||||
// We repeat it a few times in case the resume_foreground failed to work,
|
||||
// but I found that one iteration will always be enough in practice.
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (!s_activeDialog)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
s_activeDialog.Hide();
|
||||
|
||||
// Wait for the current dialog to be hidden.
|
||||
co_await wil::resume_foreground(_root->Dispatcher(), CoreDispatcherPriority::Low);
|
||||
}
|
||||
|
||||
// If two sources call ShowDialog() simultaneously, it may happen that both enter the above loop,
|
||||
// but it's crucial that only one of them continues below as only 1 dialog can be shown at a time.
|
||||
// Thankfully, everything runs on the UI thread, so only 1 caller will exit the above loop at a time.
|
||||
// So, if s_activeDialog is still set at this point, we must have lost the race.
|
||||
if (s_activeDialog)
|
||||
{
|
||||
// Another dialog is visible.
|
||||
co_return ContentDialogResult::None;
|
||||
}
|
||||
|
||||
_dialog = dialog;
|
||||
s_activeDialog = dialog;
|
||||
|
||||
// IMPORTANT: This is necessary as documented in the ContentDialog MSDN docs.
|
||||
// Since we're hosting the dialog in a Xaml island, we need to connect it to the
|
||||
@@ -367,23 +391,26 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
} };
|
||||
|
||||
themingLambda(dialog, nullptr); // if it's already in the tree
|
||||
auto loadedRevoker{ dialog.Loaded(winrt::auto_revoke, themingLambda) }; // if it's not yet in the tree
|
||||
auto result = ContentDialogResult::None;
|
||||
|
||||
// Display the dialog.
|
||||
co_return co_await dialog.ShowAsync(Controls::ContentDialogPlacement::Popup);
|
||||
// Extra scope to drop the revoker before resetting the s_activeDialog to null.
|
||||
{
|
||||
themingLambda(dialog, nullptr); // if it's already in the tree
|
||||
auto loadedRevoker{ dialog.Loaded(winrt::auto_revoke, themingLambda) }; // if it's not yet in the tree
|
||||
result = co_await dialog.ShowAsync(Controls::ContentDialogPlacement::Popup);
|
||||
}
|
||||
|
||||
// After the dialog is dismissed, the dialog lock (held by `lock`) will
|
||||
// be released so another can be shown
|
||||
s_activeDialog = nullptr;
|
||||
co_return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Dismiss the (only) visible ContentDialog
|
||||
void TerminalWindow::DismissDialog()
|
||||
{
|
||||
if (auto localDialog = std::exchange(_dialog, nullptr))
|
||||
if (s_activeDialog)
|
||||
{
|
||||
localDialog.Hide();
|
||||
s_activeDialog.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1054,12 +1081,8 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_contentBounds = bounds;
|
||||
|
||||
const auto& args = _contentStringToActions(content, true);
|
||||
|
||||
for (const auto& action : args)
|
||||
{
|
||||
_initialContentArgs.push_back(action);
|
||||
}
|
||||
const auto args = _contentStringToActions(content, true);
|
||||
_initialContentArgs = wil::to_vector(args);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1085,7 +1108,7 @@ namespace winrt::TerminalApp::implementation
|
||||
if (_appArgs->ExitCode() == 0)
|
||||
{
|
||||
auto& parsedArgs = _appArgs->ParsedArgs();
|
||||
auto actions = winrt::single_threaded_vector<ActionAndArgs>(std::move(parsedArgs.GetStartupActions()));
|
||||
auto& actions = parsedArgs.GetStartupActions();
|
||||
|
||||
_root->ProcessStartupActions(actions, false, _appArgs->CurrentDirectory(), _appArgs->CurrentEnvironment());
|
||||
|
||||
@@ -1200,7 +1223,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto& args = ActionAndArgs::Deserialize(content);
|
||||
const auto args = ActionAndArgs::Deserialize(content);
|
||||
if (args == nullptr ||
|
||||
args.Size() == 0)
|
||||
{
|
||||
@@ -1244,9 +1267,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
const bool replaceFirstWithNewTab = tabIndex >= _root->NumberOfTabs();
|
||||
|
||||
const auto& args = _contentStringToActions(content, replaceFirstWithNewTab);
|
||||
auto args = _contentStringToActions(content, replaceFirstWithNewTab);
|
||||
|
||||
_root->AttachContent(args, tabIndex);
|
||||
_root->AttachContent(std::move(args), tabIndex);
|
||||
}
|
||||
}
|
||||
void TerminalWindow::SendContentToOther(winrt::TerminalApp::RequestReceiveContentArgs args)
|
||||
|
||||
@@ -167,8 +167,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// ALSO: If you add any UIElements as roots here, make sure they're
|
||||
// updated in _ApplyTheme. The root currently is _root.
|
||||
winrt::com_ptr<TerminalPage> _root{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Controls::ContentDialog _dialog{ nullptr };
|
||||
std::shared_mutex _dialogLock;
|
||||
|
||||
wil::com_ptr<CommandlineArgs> _appArgs{ nullptr };
|
||||
bool _hasCommandLineArguments{ false };
|
||||
|
||||
@@ -14,6 +14,13 @@ static DWORD g_cTerminalHandoffRegistration = 0;
|
||||
// Mutex so we only do start/stop/establish one at a time.
|
||||
static std::shared_mutex _mtx;
|
||||
|
||||
// This is the callback that will be called when a connection is received.
|
||||
// Call this once during startup and don't ever change it again (race condition).
|
||||
void CTerminalHandoff::s_setCallback(NewHandoffFunction callback) noexcept
|
||||
{
|
||||
_pfnHandoff = callback;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Starts listening for TerminalHandoff requests by registering
|
||||
// our class and interface with COM.
|
||||
@@ -21,24 +28,19 @@ static std::shared_mutex _mtx;
|
||||
// - pfnHandoff - Function to callback when a handoff is received
|
||||
// Return Value:
|
||||
// - S_OK, E_NOT_VALID_STATE (start called when already started) or relevant COM registration error.
|
||||
HRESULT CTerminalHandoff::s_StartListening(NewHandoffFunction pfnHandoff)
|
||||
HRESULT CTerminalHandoff::s_StartListening()
|
||||
try
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
RETURN_HR_IF(E_NOT_VALID_STATE, _pfnHandoff != nullptr);
|
||||
|
||||
const auto classFactory = Make<SimpleClassFactory<CTerminalHandoff>>();
|
||||
|
||||
RETURN_IF_NULL_ALLOC(classFactory);
|
||||
RETURN_LAST_ERROR_IF_NULL(classFactory);
|
||||
|
||||
ComPtr<IUnknown> unk;
|
||||
RETURN_IF_FAILED(classFactory.As(&unk));
|
||||
|
||||
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &g_cTerminalHandoffRegistration));
|
||||
|
||||
_pfnHandoff = pfnHandoff;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
@@ -53,15 +55,6 @@ CATCH_RETURN()
|
||||
HRESULT CTerminalHandoff::s_StopListening()
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
return s_StopListeningLocked();
|
||||
}
|
||||
|
||||
// See s_StopListening()
|
||||
HRESULT CTerminalHandoff::s_StopListeningLocked()
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
_pfnHandoff = nullptr;
|
||||
|
||||
if (g_cTerminalHandoffRegistration)
|
||||
{
|
||||
@@ -92,22 +85,15 @@ HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE* in, HANDLE* out, HANDLE si
|
||||
{
|
||||
try
|
||||
{
|
||||
std::unique_lock lock{ _mtx };
|
||||
|
||||
// s_StopListeningLocked sets _pfnHandoff to nullptr.
|
||||
// localPfnHandoff is tested for nullness below.
|
||||
#pragma warning(suppress : 26429) // Symbol '...' is never tested for nullness, it can be marked as not_null (f.23).
|
||||
auto localPfnHandoff = _pfnHandoff;
|
||||
|
||||
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
|
||||
// COM does not automatically clean that up for us. We must do it.
|
||||
LOG_IF_FAILED(s_StopListeningLocked());
|
||||
LOG_IF_FAILED(s_StopListening());
|
||||
|
||||
// Report an error if no one registered a handoff function before calling this.
|
||||
THROW_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
|
||||
THROW_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
|
||||
|
||||
// Call registered handler from when we started listening.
|
||||
THROW_IF_FAILED(localPfnHandoff(in, out, signal, reference, server, client, startupInfo));
|
||||
THROW_IF_FAILED(_pfnHandoff(in, out, signal, reference, server, client, startupInfo));
|
||||
|
||||
#pragma warning(suppress : 26477)
|
||||
TraceLoggingWrite(
|
||||
|
||||
@@ -38,11 +38,11 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
|
||||
|
||||
#pragma endregion
|
||||
|
||||
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff);
|
||||
static HRESULT s_StopListening();
|
||||
static void s_setCallback(NewHandoffFunction callback) noexcept;
|
||||
static HRESULT s_StartListening();
|
||||
|
||||
private:
|
||||
static HRESULT s_StopListeningLocked();
|
||||
static HRESULT s_StopListening();
|
||||
};
|
||||
|
||||
// Disable warnings from the CoCreatableClass macro as the value it provides for
|
||||
|
||||
@@ -780,12 +780,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
void ConptyConnection::StartInboundListener()
|
||||
{
|
||||
THROW_IF_FAILED(CTerminalHandoff::s_StartListening(&ConptyConnection::NewHandoff));
|
||||
}
|
||||
static const auto init = []() noexcept {
|
||||
CTerminalHandoff::s_setCallback(&ConptyConnection::NewHandoff);
|
||||
return true;
|
||||
}();
|
||||
|
||||
void ConptyConnection::StopInboundListener()
|
||||
{
|
||||
THROW_IF_FAILED(CTerminalHandoff::s_StopListening());
|
||||
CTerminalHandoff::s_StartListening();
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
|
||||
@@ -36,7 +36,6 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
WORD ShowWindow() const noexcept;
|
||||
|
||||
static void StartInboundListener();
|
||||
static void StopInboundListener();
|
||||
|
||||
static winrt::event_token NewConnection(const NewConnectionHandler& handler);
|
||||
static void NewConnection(const winrt::event_token& token);
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace Microsoft.Terminal.TerminalConnection
|
||||
|
||||
static event NewConnectionHandler NewConnection;
|
||||
static void StartInboundListener();
|
||||
static void StopInboundListener();
|
||||
|
||||
static Windows.Foundation.Collections.ValueSet CreateSettings(String cmdline,
|
||||
String startingDirectory,
|
||||
|
||||
@@ -340,7 +340,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const Core::Point pixelPosition,
|
||||
const bool pointerPressedInBounds)
|
||||
{
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, true);
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, false);
|
||||
// Returning true from this function indicates that the caller should do no further processing of this movement.
|
||||
bool handledCompletely = false;
|
||||
|
||||
@@ -489,7 +489,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const Core::Point pixelPosition,
|
||||
const Control::MouseButtonState buttonState)
|
||||
{
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, true);
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, false);
|
||||
|
||||
// Short-circuit isReadOnly check to avoid warning dialog.
|
||||
//
|
||||
|
||||
@@ -437,7 +437,8 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
|
||||
}
|
||||
|
||||
// 0. Useful tools/vars
|
||||
const auto bufferSize = _activeBuffer().GetSize();
|
||||
const auto& buffer = _activeBuffer();
|
||||
const auto bufferSize = buffer.GetSize();
|
||||
const auto viewportHeight = _GetMutableViewport().Height();
|
||||
|
||||
// The patterns are stored relative to the "search area". Initially, this search area will be the viewport,
|
||||
@@ -504,8 +505,18 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
|
||||
};
|
||||
|
||||
// 1. Look for the hyperlink
|
||||
til::point searchStart = dir == SearchDirection::Forward ? _selection->start : til::point{ bufferSize.Left(), _VisibleStartIndex() };
|
||||
til::point searchEnd = dir == SearchDirection::Forward ? til::point{ bufferSize.RightInclusive(), _VisibleEndIndex() } : _selection->start;
|
||||
til::point searchStart;
|
||||
til::point searchEnd;
|
||||
if (dir == SearchDirection::Forward)
|
||||
{
|
||||
searchStart = _selection->start;
|
||||
searchEnd = til::point{ bufferSize.RightInclusive(), _VisibleEndIndex() };
|
||||
}
|
||||
else
|
||||
{
|
||||
searchStart = til::point{ bufferSize.Left(), _VisibleStartIndex() };
|
||||
searchEnd = _selection->start;
|
||||
}
|
||||
|
||||
// 1.A) Try searching the current viewport (no scrolling required)
|
||||
auto resultList = _patternIntervalTree.findContained(convertToSearchArea(searchStart), convertToSearchArea(searchEnd));
|
||||
@@ -547,27 +558,81 @@ void Terminal::SelectHyperlink(const SearchDirection dir)
|
||||
searchArea = Viewport::FromDimensions(searchStart, { searchEnd.x + 1, searchEnd.y + 1 });
|
||||
}
|
||||
}
|
||||
|
||||
// 1.C) Nothing was found. Bail!
|
||||
if (!result.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Select the hyperlink
|
||||
// 2. We found a hyperlink from the pattern tree. Look for embedded hyperlinks too!
|
||||
// Use the result (if one was found) to narrow down the search.
|
||||
if (dir == SearchDirection::Forward)
|
||||
{
|
||||
auto selection{ _selection.write() };
|
||||
wil::hide_name _selection;
|
||||
selection->start = result->first;
|
||||
selection->pivot = result->first;
|
||||
selection->end = result->second;
|
||||
_selectionIsTargetingUrl = true;
|
||||
_selectionEndpoint = SelectionEndpoint::End;
|
||||
searchStart = _selection->start;
|
||||
searchEnd = (result ? result->first : buffer.GetLastNonSpaceCharacter());
|
||||
}
|
||||
else
|
||||
{
|
||||
searchStart = (result ? result->second : bufferSize.Origin());
|
||||
searchEnd = _selection->start;
|
||||
}
|
||||
|
||||
// 3. Scroll to the selected area (if necessary)
|
||||
_ScrollToPoint(_selection->end);
|
||||
// Careful! Selection can point to RightExclusive(), which doesn't contain data!
|
||||
// Clamp to be safe.
|
||||
auto initialPos = dir == SearchDirection::Forward ? searchStart : searchEnd;
|
||||
bufferSize.Clamp(initialPos);
|
||||
auto iter = buffer.GetCellDataAt(initialPos);
|
||||
while (dir == SearchDirection::Forward ? iter.Pos() < searchEnd : iter.Pos() > searchStart)
|
||||
{
|
||||
// Don't let us select the same hyperlink again
|
||||
if (iter.Pos() < _selection->start || iter.Pos() > _selection->end)
|
||||
{
|
||||
if (auto attr = iter->TextAttr(); attr.IsHyperlink())
|
||||
{
|
||||
// Found an embedded hyperlink!
|
||||
const auto hyperlinkId = attr.GetHyperlinkId();
|
||||
|
||||
// Expand the start to include the entire hyperlink
|
||||
TextBufferCellIterator hyperlinkStartIter{ buffer, iter.Pos() };
|
||||
while (hyperlinkStartIter.Pos() > searchStart && attr.IsHyperlink() && attr.GetHyperlinkId() == hyperlinkId)
|
||||
{
|
||||
--hyperlinkStartIter;
|
||||
attr = hyperlinkStartIter->TextAttr();
|
||||
}
|
||||
if (hyperlinkStartIter.Pos() != bufferSize.Origin())
|
||||
{
|
||||
// undo a move to be inclusive
|
||||
++hyperlinkStartIter;
|
||||
}
|
||||
|
||||
// Expand the end to include the entire hyperlink
|
||||
// No need to undo a move! We'll decrement in the next step anyways.
|
||||
TextBufferCellIterator hyperlinkEndIter{ buffer, iter.Pos() };
|
||||
attr = hyperlinkEndIter->TextAttr();
|
||||
while (hyperlinkEndIter.Pos() < searchEnd && attr.IsHyperlink() && attr.GetHyperlinkId() == hyperlinkId)
|
||||
{
|
||||
++hyperlinkEndIter;
|
||||
attr = hyperlinkEndIter->TextAttr();
|
||||
}
|
||||
|
||||
result = { hyperlinkStartIter.Pos(), hyperlinkEndIter.Pos() };
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter += dir == SearchDirection::Forward ? 1 : -1;
|
||||
}
|
||||
|
||||
// 3. Select the hyperlink, if one exists
|
||||
if (!result.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto selection{ _selection.write() };
|
||||
wil::hide_name _selection;
|
||||
selection->start = result->first;
|
||||
selection->pivot = result->first;
|
||||
selection->end = result->second;
|
||||
_selectionIsTargetingUrl = true;
|
||||
_selectionEndpoint = SelectionEndpoint::End;
|
||||
|
||||
// 4. Scroll to the selected area (if necessary)
|
||||
_ScrollToPoint(selection->end);
|
||||
}
|
||||
|
||||
Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const noexcept
|
||||
|
||||
@@ -467,7 +467,7 @@
|
||||
<FontIcon Margin="0,0,-1,-1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
FontFamily="Segoe Fluent Icons"
|
||||
FontFamily="Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
Foreground="{TemplateBinding BorderBrush}"
|
||||
Glyph=""
|
||||
|
||||
@@ -94,12 +94,9 @@
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid ColumnSpacing="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel x:Name="ContentStackPanel"
|
||||
Orientation="Horizontal"
|
||||
Spacing="5">
|
||||
<ContentDialog x:Name="ColorPickerDialog"
|
||||
x:Uid="NullableColorPicker_ColorPickerContentDialog"
|
||||
DefaultButton="Primary"
|
||||
@@ -119,37 +116,61 @@
|
||||
Orientation="Horizontal" />
|
||||
</ContentDialog>
|
||||
|
||||
<ContentPresenter Grid.Column="0"
|
||||
Content="{x:Bind ColorSchemeVM, Mode=OneWay}"
|
||||
<ContentPresenter Content="{x:Bind ColorSchemeVM, Mode=OneWay}"
|
||||
ContentTemplate="{StaticResource ColorSchemeTemplate}" />
|
||||
|
||||
<StackPanel Grid.Column="1"
|
||||
Spacing="5">
|
||||
<ToggleButton AutomationProperties.Name="{x:Bind NullColorButtonLabel}"
|
||||
Click="NullColorButton_Clicked"
|
||||
IsChecked="{x:Bind IsNull(CurrentColor), Mode=OneWay}">
|
||||
<Grid ColumnSpacing="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Spacing="5">
|
||||
<ToggleButton AutomationProperties.Name="{x:Bind NullColorButtonLabel}"
|
||||
Click="NullColorButton_Clicked"
|
||||
IsChecked="{x:Bind IsNull(CurrentColor), Mode=OneWay}">
|
||||
<Grid ColumnSpacing="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Grid.Column="0"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Background="{x:Bind mtu:Converters.ColorToBrush(NullColorPreview), Mode=OneWay}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{ThemeResource ControlCornerRadius}" />
|
||||
<Border Grid.Column="0"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Background="{x:Bind mtu:Converters.ColorToBrush(NullColorPreview), Mode=OneWay}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{ThemeResource ControlCornerRadius}" />
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{x:Bind NullColorButtonLabel}" />
|
||||
</Grid>
|
||||
</ToggleButton>
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{x:Bind NullColorButtonLabel}" />
|
||||
</Grid>
|
||||
</ToggleButton>
|
||||
|
||||
<Button x:Uid="NullableColorPicker_MoreColorsButton"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="MoreColors_Clicked" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Button x:Uid="NullableColorPicker_MoreColorsButton"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="MoreColors_Clicked" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup>
|
||||
<VisualState x:Name="Narrow">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="0" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentStackPanel.Orientation" Value="Vertical" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Wide">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="600" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ContentStackPanel.Orientation" Value="Horizontal" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</StackPanel>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Cursorfarbe aus Farbschema verwenden</value>
|
||||
<value>Schemafarbe verwenden</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Vordergrundfarbe aus Farbschema verwenden</value>
|
||||
<value>Schemafarbe verwenden</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Hintergrundfarbe aus Farbschema verwenden</value>
|
||||
<value>Schemafarbe verwenden</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Auswahlhintergrundfarbe aus Farbschema verwenden</value>
|
||||
<value>Schemafarbe verwenden</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>Zeigt ein Schild in der Titelleiste an, wenn Windows Terminal als Administrator ausgeführt wird.</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Registerkarten im Vollbildmodus anzeigen</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Wenn diese Option aktiviert ist, wird die Registerkartenleiste angezeigt, wenn sich die App im Vollbildmodus befindet.</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Pfadübersetzung</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2033,19 +2033,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Use cursor color from color scheme</value>
|
||||
<value>Use scheme color</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Use foreground color from color scheme</value>
|
||||
<value>Use scheme color</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Use background color from color scheme</value>
|
||||
<value>Use scheme color</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Use selection background color from color scheme</value>
|
||||
<value>Use scheme color</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usar el color del cursor de la combinación de colores</value>
|
||||
<value>Usar color de la combinación</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usar el color de primer plano de la combinación de colores</value>
|
||||
<value>Usar color de la combinación</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usar el color de fondo de la combinación de colores</value>
|
||||
<value>Usar color de la combinación</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usar el color de fondo de selección de la combinación de colores</value>
|
||||
<value>Usar color de la combinación</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>Mostrar un escudo en la barra de título cuando Terminal Windows se ejecute como administrador</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Mostrar las pestañas en pantalla completa</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Cuando está habilitada, la barra de pestañas estará visible cuando la aplicación esté en pantalla completa.</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Traducción de ruta de acceso</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Utilisez la couleur du curseur à partir du jeu de couleurs</value>
|
||||
<value>Utiliser la couleur du jeu</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Utilisez la couleur de premier plan du jeu de couleurs</value>
|
||||
<value>Utiliser la couleur du jeu</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Utilisez la couleur d'arrière-plan du jeu de couleurs</value>
|
||||
<value>Utiliser la couleur du jeu</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Utilisez la couleur d'arrière-plan de sélection à partir du jeu de couleurs</value>
|
||||
<value>Utiliser la couleur du jeu</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>Afficher un bouclier dans la barre de titre lorsque Terminal Windows s’exécute en tant qu’administrateur</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Afficher les onglets en mode plein écran</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Lorsque cette option est activée, la barre d’onglets est visible lorsque l’application est en plein écran.</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Traduction du chemin d’accès</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usa il colore del cursore dalla combinazione colori</value>
|
||||
<value>Usa colore combinazione</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usa il colore primo piano dalla combinazione colori</value>
|
||||
<value>Usa colore combinazione</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usa il colore di sfondo della combinazione colori</value>
|
||||
<value>Usa colore combinazione</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usa il colore di sfondo della selezione dalla combinazione colori</value>
|
||||
<value>Usa colore combinazione</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>Visualizza uno scudo nella barra del titolo quando Terminale Windows viene eseguito come amministratore</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Mostra le schede a schermo intero</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Se questa opzione è abilitata, la barra delle schede sarà visibile quando l'app è a schermo intero.</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Traduzione percorso</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>配色からカーソルの色を使用する</value>
|
||||
<value>配色を使用</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>配色から前景色を使用する</value>
|
||||
<value>配色を使用</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>配色から背景色を使用する</value>
|
||||
<value>配色を使用</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>配色から選択範囲の背景色を使用する</value>
|
||||
<value>配色を使用</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>Windows ターミナルが管理者として実行されているときにタイトル バーにシールドを表示する</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>全画面表示でタブを表示</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>有効にすると、アプリが全画面表示のときにタブ バーが表示されます。</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>パスの変換</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>색 구성표에서 커서 색 사용</value>
|
||||
<value>구성표 색 사용</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>색 구성표에서 전경색 사용</value>
|
||||
<value>구성표 색 사용</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>색 구성표의 배경색 사용</value>
|
||||
<value>구성표 색 사용</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>색 구성표에서 선택 배경색 사용</value>
|
||||
<value>구성표 색 사용</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>Windows 터미널 관리자 권한으로 실행 중일 때 제목 표시줄에 실드 표시</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>전체 화면으로 탭 표시</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>사용하도록 설정하면 앱이 전체 화면일 때 탭 표시줄이 표시됩니다.</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>경로 변환</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usar a cor do cursor do esquema de cores</value>
|
||||
<value>Usar cor do esquema</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usar a cor de primeiro plano do esquema de cores</value>
|
||||
<value>Usar cor do esquema</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usar a cor da tela de fundo do esquema de cores</value>
|
||||
<value>Usar cor do esquema</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Usar a cor da tela de fundo de seleção do esquema de cores</value>
|
||||
<value>Usar cor do esquema</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>Exibir um escudo na barra de título quando o Terminal do Windows estiver sendo executado como Administrador</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Mostrar as guias em tela inteira</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Quando habilitada, a barra de guias ficará visível quando o aplicativo estiver em tela inteira.</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Tradução de caminho</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2033,19 +2033,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ùŝë ćυŗšθг çσľōř ƒŗōm ĉöŀøя śĉнзмé !!! !!! !!! !</value>
|
||||
<value>Ùŝë ŝčĥзмё çσľōř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ŭŝě ƒθгęĝѓóϋňď ćǿłõѓ ƒŕõм сöℓòя şçĥέмё !!! !!! !!! !!</value>
|
||||
<value>Ŭŝě şςђęmε ¢оłöř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ůśĕ вäćкģŗòŭиð ćôℓοѓ ƒŕǿm čòℓôѓ śςĥëmē !!! !!! !!! !!</value>
|
||||
<value>Ůśĕ śĉħемë ¢ōĺóř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ůŝë śęŀ℮çťïòл ьαćкğŕόµńđ çøłôř ƒŗоm ¢οłõг ş¢нέмё !!! !!! !!! !!! !!</value>
|
||||
<value>Ůŝë śĉћ℮mĕ çòĺőг !!! !</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2280,6 +2280,14 @@
|
||||
<value>Đįŝрļãу ã ŝħĭěļð ίπ ŧђê ţîťłë ъãѓ щћэπ Ẅīήđθщş Ţĕřмïńāľ ίѕ ŕůπʼnïηģ åš Àδмιήίŝтяàтοґ !!! !!! !!! !!! !!! !!! !!! !!! </value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Şĥбω ťãьŝ іή ƒūļℓ šĉґééл !!! !!! !</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Шнèŋ ěπǻьłéđ, тнĕ ŧªв вář ẁϊℓł ь℮ νìşίьĺę шћеň τћé άрр íś ƒûĺĺ şčŗёеņ. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Ρǻţħ τґãñşĺαŧîσй !!! !</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2033,19 +2033,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ùŝë ćυŗšθг çσľōř ƒŗōm ĉöŀøя śĉнзмé !!! !!! !!! !</value>
|
||||
<value>Ùŝë ŝčĥзмё çσľōř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ŭŝě ƒθгęĝѓóϋňď ćǿłõѓ ƒŕõм сöℓòя şçĥέмё !!! !!! !!! !!</value>
|
||||
<value>Ŭŝě şςђęmε ¢оłöř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ůśĕ вäćкģŗòŭиð ćôℓοѓ ƒŕǿm čòℓôѓ śςĥëmē !!! !!! !!! !!</value>
|
||||
<value>Ůśĕ śĉħемë ¢ōĺóř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ůŝë śęŀ℮çťïòл ьαćкğŕόµńđ çøłôř ƒŗоm ¢οłõг ş¢нέмё !!! !!! !!! !!! !!</value>
|
||||
<value>Ůŝë śĉћ℮mĕ çòĺőг !!! !</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2280,6 +2280,14 @@
|
||||
<value>Đįŝрļãу ã ŝħĭěļð ίπ ŧђê ţîťłë ъãѓ щћэπ Ẅīήđθщş Ţĕřмïńāľ ίѕ ŕůπʼnïηģ åš Àδмιήίŝтяàтοґ !!! !!! !!! !!! !!! !!! !!! !!! </value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Şĥбω ťãьŝ іή ƒūļℓ šĉґééл !!! !!! !</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Шнèŋ ěπǻьłéđ, тнĕ ŧªв вář ẁϊℓł ь℮ νìşίьĺę шћеň τћé άрр íś ƒûĺĺ şčŗёеņ. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Ρǻţħ τґãñşĺαŧîσй !!! !</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2033,19 +2033,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ùŝë ćυŗšθг çσľōř ƒŗōm ĉöŀøя śĉнзмé !!! !!! !!! !</value>
|
||||
<value>Ùŝë ŝčĥзмё çσľōř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ŭŝě ƒθгęĝѓóϋňď ćǿłõѓ ƒŕõм сöℓòя şçĥέмё !!! !!! !!! !!</value>
|
||||
<value>Ŭŝě şςђęmε ¢оłöř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ůśĕ вäćкģŗòŭиð ćôℓοѓ ƒŕǿm čòℓôѓ śςĥëmē !!! !!! !!! !!</value>
|
||||
<value>Ůśĕ śĉħемë ¢ōĺóř !!! !</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Ůŝë śęŀ℮çťïòл ьαćкğŕόµńđ çøłôř ƒŗоm ¢οłõг ş¢нέмё !!! !!! !!! !!! !!</value>
|
||||
<value>Ůŝë śĉћ℮mĕ çòĺőг !!! !</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2280,6 +2280,14 @@
|
||||
<value>Đįŝрļãу ã ŝħĭěļð ίπ ŧђê ţîťłë ъãѓ щћэπ Ẅīήđθщş Ţĕřмïńāľ ίѕ ŕůπʼnïηģ åš Àδмιήίŝтяàтοґ !!! !!! !!! !!! !!! !!! !!! !!! </value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Şĥбω ťãьŝ іή ƒūļℓ šĉґééл !!! !!! !</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Шнèŋ ěπǻьłéđ, тнĕ ŧªв вář ẁϊℓł ь℮ νìşίьĺę шћеň τћé άрр íś ƒûĺĺ şčŗёеņ. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Ρǻţħ τґãñşĺαŧîσй !!! !</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Использовать цвет курсора из цветовой схемы</value>
|
||||
<value>Использовать цвет схемы</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Использовать цвет переднего плана из цветовой схемы</value>
|
||||
<value>Использовать цвет схемы</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Использовать цвет фона из цветовой схемы</value>
|
||||
<value>Использовать цвет схемы</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>Использовать выбранный цвет фона из цветовой схемы</value>
|
||||
<value>Использовать цвет схемы</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>Отображать экран в заголовке, когда Терминал Windows от имени администратора</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>Показывать вкладки в полноэкранном режиме</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>Если этот параметр включен, панель вкладок будет отображаться, когда приложение будет полноэкранным.</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Преобразование пути</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>使用配色方案中的光标色</value>
|
||||
<value>使用配色方案颜色</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>使用配色方案中的前景色</value>
|
||||
<value>使用配色方案颜色</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>使用配色方案中的背景色</value>
|
||||
<value>使用配色方案颜色</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>使用配色方案中的选择背景色</value>
|
||||
<value>使用配色方案颜色</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>当 Windows 终端以管理员身份运行时,在标题栏中显示一个盾牌图标</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>全屏显示选项卡</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>启用后,当应用处于全屏状态时,选项卡栏将可见。</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>路径转换</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -2029,19 +2029,19 @@
|
||||
<comment>Text label for secondary button the color picker content dialog. When clicked, the operation of selecting a color is cancelled by the user.</comment>
|
||||
</data>
|
||||
<data name="Profile_CursorColor_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>使用色彩配置的游標色彩</value>
|
||||
<value>使用配置色彩</value>
|
||||
<comment>Label for a button directing the user to use the cursor color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Foreground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>使用色彩配置的前景色彩</value>
|
||||
<value>使用配置色彩</value>
|
||||
<comment>Label for a button directing the user to use the foreground color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_Background_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>使用色彩配置的背景色彩</value>
|
||||
<value>使用配置色彩</value>
|
||||
<comment>Label for a button directing the user to use the background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_SelectionBackground_NullableColorPicker.NullColorButtonLabel" xml:space="preserve">
|
||||
<value>使用色彩配置的選取項目背景色彩</value>
|
||||
<value>使用配置色彩</value>
|
||||
<comment>Label for a button directing the user to use the selection background color defined in the terminal's current color scheme.</comment>
|
||||
</data>
|
||||
<data name="Profile_IconTypeNone" xml:space="preserve">
|
||||
@@ -2276,6 +2276,14 @@
|
||||
<value>當 Windows 終端機 以系統管理員身分執行時,在標題欄中顯示遮罩</value>
|
||||
<comment>Header for a control to toggle displaying a shield in the title bar of the app. "Admin" refers to elevated sessions like "run as Admin"</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.Header" xml:space="preserve">
|
||||
<value>以全螢幕顯示索引標籤</value>
|
||||
<comment>Header for a control to toggle if the app should show the tabs when in full screen state.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTabsFullscreen.HelpText" xml:space="preserve">
|
||||
<value>啟用時,當應用程式使用全螢幕時,將會顯示索引標籤。</value>
|
||||
<comment>A description for what the "show tabs in full screen" setting does.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyle.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>路徑翻譯</value>
|
||||
<comment>Name for a control to select how file and directory paths are translated.</comment>
|
||||
|
||||
@@ -354,7 +354,7 @@
|
||||
<value>タブのタイトルをリセット</value>
|
||||
</data>
|
||||
<data name="OpenTabRenamerCommandKey" xml:space="preserve">
|
||||
<value>[名前の変更] タブ</value>
|
||||
<value>タブ名を変更</value>
|
||||
</data>
|
||||
<data name="ResizePaneCommandKey" xml:space="preserve">
|
||||
<value>ウィンドウのサイズの変更する</value>
|
||||
|
||||
@@ -81,6 +81,29 @@
|
||||
// - "foreground"
|
||||
// - "background"
|
||||
// - "cursorColor"
|
||||
{
|
||||
"name": "Ottosson",
|
||||
"background": "#000000",
|
||||
"foreground": "#bebebe",
|
||||
"cursorColor": "#ffffff",
|
||||
"selectionBackground": "#92a4fd",
|
||||
"black": "#000000",
|
||||
"red": "#be2c21",
|
||||
"green": "#3fae3a",
|
||||
"yellow": "#be9a4a",
|
||||
"blue": "#204dbe",
|
||||
"purple": "#bb54be",
|
||||
"cyan": "#00a7b2",
|
||||
"white": "#bebebe",
|
||||
"brightBlack": "#808080",
|
||||
"brightRed": "#ff3e30",
|
||||
"brightGreen": "#58ea51",
|
||||
"brightYellow": "#ffc944",
|
||||
"brightBlue": "#2f6aff",
|
||||
"brightPurple": "#fc74ff",
|
||||
"brightCyan": "#00e1f0",
|
||||
"brightWhite": "#ffffff"
|
||||
},
|
||||
{
|
||||
"name": "Campbell",
|
||||
"foreground": "#CCCCCC",
|
||||
|
||||
@@ -95,6 +95,12 @@ void IslandWindow::Close()
|
||||
|
||||
if (_source)
|
||||
{
|
||||
// BODGY
|
||||
// WinUI will strongly hold onto the first DesktopWindowXamlSource that is created.
|
||||
// If we don't manually set the Content() to null first, closing that first window
|
||||
// will leak all of its contents permanently.
|
||||
_source.Content(nullptr);
|
||||
|
||||
_source.Close();
|
||||
_source = nullptr;
|
||||
}
|
||||
|
||||
@@ -246,6 +246,8 @@ void WindowEmperor::CreateNewWindow(winrt::TerminalApp::WindowRequestedArgs args
|
||||
|
||||
auto host = std::make_shared<AppHost>(this, _app.Logic(), std::move(args));
|
||||
host->Initialize();
|
||||
|
||||
_windowCount += 1;
|
||||
_windows.emplace_back(std::move(host));
|
||||
}
|
||||
|
||||
@@ -735,9 +737,14 @@ void WindowEmperor::_createMessageWindow(const wchar_t* className)
|
||||
StringCchCopy(_notificationIcon.szTip, ARRAYSIZE(_notificationIcon.szTip), appNameLoc.c_str());
|
||||
}
|
||||
|
||||
// Posts a WM_QUIT as soon as we have no reason to exist anymore.
|
||||
// That basically means no windows and no message boxes.
|
||||
void WindowEmperor::_postQuitMessageIfNeeded() const
|
||||
{
|
||||
if (_messageBoxCount <= 0 && _windows.empty() && !_app.Logic().Settings().GlobalSettings().AllowHeadless())
|
||||
if (
|
||||
_messageBoxCount <= 0 &&
|
||||
_windowCount <= 0 &&
|
||||
!_app.Logic().Settings().GlobalSettings().AllowHeadless())
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
@@ -771,20 +778,37 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
|
||||
{
|
||||
case WM_CLOSE_TERMINAL_WINDOW:
|
||||
{
|
||||
const auto host = reinterpret_cast<AppHost*>(lParam);
|
||||
auto it = _windows.begin();
|
||||
const auto end = _windows.end();
|
||||
const auto globalSettings = _app.Logic().Settings().GlobalSettings();
|
||||
// Keep the last window in the array so that we can persist it on exit.
|
||||
// We check for AllowHeadless(), as that being true prevents us from ever quitting in the first place.
|
||||
// (= If we avoided closing the last window you wouldn't be able to reach a headless state.)
|
||||
const auto shouldKeepWindow =
|
||||
_windows.size() == 1 &&
|
||||
globalSettings.ShouldUsePersistedLayout() &&
|
||||
!globalSettings.AllowHeadless();
|
||||
|
||||
for (; it != end; ++it)
|
||||
if (!shouldKeepWindow)
|
||||
{
|
||||
if (host == it->get())
|
||||
// Did the window counter get out of sync? It shouldn't.
|
||||
assert(_windowCount == gsl::narrow_cast<int32_t>(_windows.size()));
|
||||
|
||||
const auto host = reinterpret_cast<AppHost*>(lParam);
|
||||
auto it = _windows.begin();
|
||||
const auto end = _windows.end();
|
||||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
host->Close();
|
||||
_windows.erase(it);
|
||||
break;
|
||||
if (host == it->get())
|
||||
{
|
||||
host->Close();
|
||||
_windows.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Counterpart specific to CreateNewWindow().
|
||||
_windowCount -= 1;
|
||||
_postQuitMessageIfNeeded();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ private:
|
||||
safe_void_coroutine _dispatchCommandlineCurrentDesktop(winrt::TerminalApp::CommandlineArgs args);
|
||||
LRESULT _messageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam) noexcept;
|
||||
void _createMessageWindow(const wchar_t* className);
|
||||
bool _shouldSkipClosingWindows() const;
|
||||
void _postQuitMessageIfNeeded() const;
|
||||
safe_void_coroutine _showMessageBox(winrt::hstring message, bool error);
|
||||
void _notificationAreaMenuRequested(WPARAM wParam);
|
||||
@@ -77,6 +78,7 @@ private:
|
||||
bool _forcePersistence = false;
|
||||
bool _needsPersistenceCleanup = false;
|
||||
std::optional<bool> _currentSystemThemeIsDark;
|
||||
int32_t _windowCount = 0;
|
||||
int32_t _messageBoxCount = 0;
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
@@ -79,7 +79,11 @@ using namespace Microsoft::Console::Interactivity;
|
||||
const HANDLE OutHandle,
|
||||
_In_opt_ const HANDLE SignalHandle)
|
||||
{
|
||||
FAIL_FAST_IF_MSG(_initialized, "Someone attempted to double-_Initialize VtIo");
|
||||
if (_state != State::Uninitialized)
|
||||
{
|
||||
assert(false); // Don't call initialize twice.
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
_hInput.reset(InHandle);
|
||||
_hOutput.reset(OutHandle);
|
||||
@@ -95,47 +99,33 @@ using namespace Microsoft::Console::Interactivity;
|
||||
}
|
||||
}
|
||||
|
||||
// - Create and start the signal thread. The signal thread can be created
|
||||
// independent of the i/o threads, and doesn't require a client first
|
||||
// attaching to the console. We need to create it first and foremost,
|
||||
// because it's possible that a terminal application could
|
||||
// CreatePseudoConsole, then ClosePseudoConsole without ever attaching a
|
||||
// client. Should that happen, we still need to exit.
|
||||
if (IsValidHandle(_hSignal.get()))
|
||||
{
|
||||
try
|
||||
{
|
||||
_pPtySignalInputThread = std::make_unique<PtySignalInputThread>(std::move(_hSignal));
|
||||
|
||||
// Start it if it was successfully created.
|
||||
RETURN_IF_FAILED(_pPtySignalInputThread->Start());
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// The only way we're initialized is if the args said we're in conpty mode.
|
||||
// If the args say so, then at least one of in, out, or signal was specified
|
||||
_initialized = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create the VtEngine and the VtInputThread for this console.
|
||||
// MUST BE DONE AFTER CONSOLE IS INITIALIZED, to make sure we've gotten the
|
||||
// buffer size from the attached client application.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// S_OK if we initialized successfully,
|
||||
// S_FALSE if VtIo hasn't been initialized (or we're not in conpty mode)
|
||||
// otherwise an appropriate HRESULT indicating failure.
|
||||
[[nodiscard]] HRESULT VtIo::CreateIoHandlers() noexcept
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// SetWindowVisibility uses the console lock to protect access to _pVtRenderEngine.
|
||||
assert(ServiceLocator::LocateGlobals().getConsoleInformation().IsConsoleLocked());
|
||||
|
||||
try
|
||||
{
|
||||
if (IsValidHandle(_hInput.get()))
|
||||
{
|
||||
_pVtInputThread = std::make_unique<VtInputThread>(std::move(_hInput), _lookingForCursorPosition);
|
||||
}
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
_state = State::Initialized;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool VtIo::IsUsingVt() const
|
||||
{
|
||||
return _initialized;
|
||||
return _state != State::Uninitialized;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -151,50 +141,64 @@ bool VtIo::IsUsingVt() const
|
||||
[[nodiscard]] HRESULT VtIo::StartIfNeeded()
|
||||
{
|
||||
// If we haven't been set up, do nothing (because there's nothing to start)
|
||||
if (!_initialized)
|
||||
if (_state != State::Initialized)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
_state = State::Starting;
|
||||
|
||||
// SetWindowVisibility uses the console lock to protect access to _pVtRenderEngine.
|
||||
assert(ServiceLocator::LocateGlobals().getConsoleInformation().IsConsoleLocked());
|
||||
|
||||
try
|
||||
{
|
||||
if (IsValidHandle(_hInput.get()))
|
||||
{
|
||||
_pVtInputThread = std::make_unique<VtInputThread>(std::move(_hInput), _lookingForCursorPosition);
|
||||
}
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
if (_pVtInputThread)
|
||||
{
|
||||
LOG_IF_FAILED(_pVtInputThread->Start());
|
||||
}
|
||||
|
||||
{
|
||||
Writer writer{ this };
|
||||
|
||||
// MSFT: 15813316
|
||||
// If the terminal application wants us to inherit the cursor position,
|
||||
// we're going to emit a VT sequence to ask for the cursor position.
|
||||
// If we get a response, the InteractDispatch will call SetCursorPosition,
|
||||
// which will call to our VtIo::SetCursorPosition method.
|
||||
//
|
||||
// By sending the request before sending the DA1 one, we can simply
|
||||
// wait for the DA1 response below and effectively wait for both.
|
||||
if (_lookingForCursorPosition)
|
||||
{
|
||||
writer.WriteUTF8("\x1b[6n"); // Cursor Position Report (DSR CPR)
|
||||
Writer writer{ this };
|
||||
|
||||
// MSFT: 15813316
|
||||
// If the terminal application wants us to inherit the cursor position,
|
||||
// we're going to emit a VT sequence to ask for the cursor position.
|
||||
// If we get a response, the InteractDispatch will call SetCursorPosition,
|
||||
// which will call to our VtIo::SetCursorPosition method.
|
||||
//
|
||||
// By sending the request before sending the DA1 one, we can simply
|
||||
// wait for the DA1 response below and effectively wait for both.
|
||||
if (_lookingForCursorPosition)
|
||||
{
|
||||
writer.WriteUTF8("\x1b[6n"); // Cursor Position Report (DSR CPR)
|
||||
}
|
||||
|
||||
// GH#4999 - Send a sequence to the connected terminal to request
|
||||
// win32-input-mode from them. This will enable the connected terminal to
|
||||
// send us full INPUT_RECORDs as input. If the terminal doesn't understand
|
||||
// this sequence, it'll just ignore it.
|
||||
writer.WriteUTF8(
|
||||
"\x1b[c" // DA1 Report (Primary Device Attributes)
|
||||
"\x1b[?1004h" // Focus Event Mode
|
||||
"\x1b[?9001h" // Win32 Input Mode
|
||||
);
|
||||
|
||||
writer.Submit();
|
||||
}
|
||||
|
||||
// GH#4999 - Send a sequence to the connected terminal to request
|
||||
// win32-input-mode from them. This will enable the connected terminal to
|
||||
// send us full INPUT_RECORDs as input. If the terminal doesn't understand
|
||||
// this sequence, it'll just ignore it.
|
||||
writer.WriteUTF8(
|
||||
"\x1b[c" // DA1 Report (Primary Device Attributes)
|
||||
"\x1b[?1004h" // Focus Event Mode
|
||||
"\x1b[?9001h" // Win32 Input Mode
|
||||
);
|
||||
|
||||
writer.Submit();
|
||||
}
|
||||
|
||||
{
|
||||
// Allow the input thread to momentarily gain the console lock.
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
const auto suspension = gci.SuspendLock();
|
||||
_deviceAttributes = _pVtInputThread->WaitUntilDA1(3000);
|
||||
{
|
||||
// Allow the input thread to momentarily gain the console lock.
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
const auto suspension = gci.SuspendLock();
|
||||
_deviceAttributes = _pVtInputThread->WaitUntilDA1(3000);
|
||||
}
|
||||
}
|
||||
|
||||
if (_pPtySignalInputThread)
|
||||
@@ -208,6 +212,17 @@ bool VtIo::IsUsingVt() const
|
||||
_pPtySignalInputThread->ConnectConsole();
|
||||
}
|
||||
|
||||
if (_state != State::Starting)
|
||||
{
|
||||
// Here's where we _could_ call CloseConsoleProcessState(), but this function
|
||||
// only gets called once when the first client connects and CONSOLE_INITIALIZED
|
||||
// is not set yet. The process list may already contain that first client,
|
||||
// but since it hasn't finished connecting yet, it won't react to a CTRL_CLOSE_EVENT.
|
||||
// Instead, we return an error here which will abort the connection setup.
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
_state = State::Running;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -244,47 +259,21 @@ void VtIo::CreatePseudoWindow()
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create and start the signal thread. The signal thread can be created
|
||||
// independent of the i/o threads, and doesn't require a client first
|
||||
// attaching to the console. We need to create it first and foremost,
|
||||
// because it's possible that a terminal application could
|
||||
// CreatePseudoConsole, then ClosePseudoConsole without ever attaching a
|
||||
// client. Should that happen, we still need to exit.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - S_FALSE if we're not in VtIo mode,
|
||||
// S_OK if we succeeded,
|
||||
// otherwise an appropriate HRESULT indicating failure.
|
||||
[[nodiscard]] HRESULT VtIo::CreateAndStartSignalThread() noexcept
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
// If we were passed a signal handle, try to open it and make a signal reading thread.
|
||||
if (IsValidHandle(_hSignal.get()))
|
||||
{
|
||||
try
|
||||
{
|
||||
_pPtySignalInputThread = std::make_unique<PtySignalInputThread>(std::move(_hSignal));
|
||||
|
||||
// Start it if it was successfully created.
|
||||
RETURN_IF_FAILED(_pPtySignalInputThread->Start());
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void VtIo::SendCloseEvent()
|
||||
{
|
||||
LockConsole();
|
||||
const auto unlock = wil::scope_exit([] { UnlockConsole(); });
|
||||
|
||||
// If we're still in the process of starting up, and we're asked to shut down
|
||||
// (broken pipe), `VtIo::StartIfNeeded()` will handle the cleanup for us.
|
||||
// This can happen during the call to `WaitUntilDA1`, because we relinquish
|
||||
// ownership of the console lock.
|
||||
if (_state == State::Starting)
|
||||
{
|
||||
_state = State::StartupFailed;
|
||||
return;
|
||||
}
|
||||
|
||||
// This function is called when the ConPTY signal pipe is closed (PtySignalInputThread) and when the input
|
||||
// pipe is closed (VtIo). Usually these two happen at about the same time. This if condition is a bit of
|
||||
// a premature optimization and prevents us from sending out a CTRL_CLOSE_EVENT right after another.
|
||||
|
||||
@@ -57,8 +57,6 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
static wchar_t SanitizeUCS2(wchar_t ch);
|
||||
|
||||
[[nodiscard]] HRESULT Initialize(const ConsoleArguments* const pArgs);
|
||||
[[nodiscard]] HRESULT CreateAndStartSignalThread() noexcept;
|
||||
[[nodiscard]] HRESULT CreateIoHandlers() noexcept;
|
||||
|
||||
bool IsUsingVt() const;
|
||||
[[nodiscard]] HRESULT StartIfNeeded();
|
||||
@@ -69,6 +67,15 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
void CreatePseudoWindow();
|
||||
|
||||
private:
|
||||
enum class State : uint8_t
|
||||
{
|
||||
Uninitialized,
|
||||
Initialized,
|
||||
Starting,
|
||||
StartupFailed,
|
||||
Running,
|
||||
};
|
||||
|
||||
[[nodiscard]] HRESULT _Initialize(const HANDLE InHandle, const HANDLE OutHandle, _In_opt_ const HANDLE SignalHandle);
|
||||
|
||||
void _uncork();
|
||||
@@ -77,7 +84,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
// After CreateIoHandlers is called, these will be invalid.
|
||||
wil::unique_hfile _hInput;
|
||||
wil::unique_hfile _hOutput;
|
||||
// After CreateAndStartSignalThread is called, this will be invalid.
|
||||
// After Initialize is called, this will be invalid.
|
||||
wil::unique_hfile _hSignal;
|
||||
|
||||
std::unique_ptr<Microsoft::Console::VtInputThread> _pVtInputThread;
|
||||
@@ -96,7 +103,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
bool _writerRestoreCursor = false;
|
||||
bool _writerTainted = false;
|
||||
|
||||
bool _initialized = false;
|
||||
State _state = State::Uninitialized;
|
||||
bool _lookingForCursorPosition = false;
|
||||
bool _closeEventSent = false;
|
||||
int _corked = 0;
|
||||
|
||||
@@ -381,7 +381,6 @@ HRESULT ConsoleCreateIoThread(_In_ HANDLE Server,
|
||||
// can start, so they're started below, in ConsoleAllocateConsole
|
||||
auto& gci = g.getConsoleInformation();
|
||||
RETURN_IF_FAILED(gci.GetVtIo()->Initialize(args));
|
||||
RETURN_IF_FAILED(gci.GetVtIo()->CreateAndStartSignalThread());
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -945,27 +944,11 @@ PWSTR TranslateConsoleTitle(_In_ PCWSTR pwszConsoleTitle, const BOOL fUnexpand,
|
||||
// We'll need the size of the screen buffer in the vt i/o initialization
|
||||
if (SUCCEEDED_NTSTATUS(Status))
|
||||
{
|
||||
auto hr = gci.GetVtIo()->CreateIoHandlers();
|
||||
if (hr == S_FALSE)
|
||||
{
|
||||
// We're not in VT I/O mode, this is fine.
|
||||
}
|
||||
else if (SUCCEEDED(hr))
|
||||
{
|
||||
// Actually start the VT I/O threads
|
||||
hr = gci.GetVtIo()->StartIfNeeded();
|
||||
// Don't convert S_FALSE to an NTSTATUS - the equivalent NTSTATUS
|
||||
// is treated as an error
|
||||
if (hr != S_FALSE)
|
||||
{
|
||||
Status = NTSTATUS_FROM_HRESULT(hr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
// Actually start the VT I/O threads
|
||||
auto hr = gci.GetVtIo()->StartIfNeeded();
|
||||
// Don't convert S_FALSE to an NTSTATUS - the equivalent NTSTATUS
|
||||
// is treated as an error
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Status = NTSTATUS_FROM_HRESULT(hr);
|
||||
}
|
||||
@@ -1008,7 +991,7 @@ DWORD WINAPI ConsoleIoThread(LPVOID lpParameter)
|
||||
{
|
||||
if (ReplyMsg != nullptr)
|
||||
{
|
||||
LOG_IF_FAILED(ReplyMsg->ReleaseMessageBuffers());
|
||||
ReplyMsg->ReleaseMessageBuffers();
|
||||
}
|
||||
|
||||
// TODO: 9115192 correct mixed NTSTATUS/HRESULT
|
||||
|
||||
@@ -180,12 +180,8 @@ CATCH_RETURN();
|
||||
// (if any) to the message.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - HRESULT indicating if the payload was successfully written if applicable.
|
||||
[[nodiscard]] HRESULT _CONSOLE_API_MSG::ReleaseMessageBuffers()
|
||||
void _CONSOLE_API_MSG::ReleaseMessageBuffers()
|
||||
{
|
||||
auto hr = S_OK;
|
||||
|
||||
if (State.InputBuffer != nullptr)
|
||||
{
|
||||
_inputBuffer.clear();
|
||||
@@ -203,15 +199,15 @@ CATCH_RETURN();
|
||||
IoOperation.Buffer.Data = State.OutputBuffer;
|
||||
IoOperation.Buffer.Size = (ULONG)Complete.IoStatus.Information;
|
||||
|
||||
LOG_IF_FAILED(_pDeviceComm->WriteOutput(&IoOperation));
|
||||
// This call fails when the server pipe is closed on us,
|
||||
// which results in log spam in practice.
|
||||
std::ignore = _pDeviceComm->WriteOutput(&IoOperation);
|
||||
}
|
||||
|
||||
_outputBuffer.clear();
|
||||
State.OutputBuffer = nullptr;
|
||||
State.OutputBufferSize = 0;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void _CONSOLE_API_MSG::SetReplyStatus(const NTSTATUS Status)
|
||||
|
||||
@@ -42,7 +42,7 @@ typedef struct _CONSOLE_API_MSG
|
||||
[[nodiscard]] HRESULT GetOutputBuffer(_Outptr_result_bytebuffer_(*pcbSize) void** const ppvBuffer, _Out_ ULONG* const pcbSize);
|
||||
[[nodiscard]] HRESULT GetInputBuffer(_Outptr_result_bytebuffer_(*pcbSize) void** const ppvBuffer, _Out_ ULONG* const pcbSize);
|
||||
|
||||
[[nodiscard]] HRESULT ReleaseMessageBuffers();
|
||||
void ReleaseMessageBuffers();
|
||||
|
||||
void SetReplyStatus(const NTSTATUS Status);
|
||||
void SetReplyInformation(const ULONG_PTR pInformation);
|
||||
|
||||
@@ -137,14 +137,15 @@ ConDrvDeviceComm::~ConDrvDeviceComm() = default;
|
||||
// See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363216(v=vs.85).aspx
|
||||
// Written is unused but cannot be nullptr because we aren't using overlapped.
|
||||
DWORD cbWritten = 0;
|
||||
RETURN_IF_WIN32_BOOL_FALSE(DeviceIoControl(_Server.get(),
|
||||
dwIoControlCode,
|
||||
pInBuffer,
|
||||
cbInBufferSize,
|
||||
pOutBuffer,
|
||||
cbOutBufferSize,
|
||||
&cbWritten,
|
||||
nullptr));
|
||||
RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(DeviceIoControl(
|
||||
_Server.get(),
|
||||
dwIoControlCode,
|
||||
pInBuffer,
|
||||
cbInBufferSize,
|
||||
pOutBuffer,
|
||||
cbOutBufferSize,
|
||||
&cbWritten,
|
||||
nullptr));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -223,9 +223,11 @@ bool ConsoleWaitBlock::Notify(const WaitTerminationReason TerminationReason)
|
||||
a->NumBytes = gsl::narrow<ULONG>(NumBytes);
|
||||
}
|
||||
|
||||
LOG_IF_FAILED(_WaitReplyMessage.ReleaseMessageBuffers());
|
||||
_WaitReplyMessage.ReleaseMessageBuffers();
|
||||
|
||||
LOG_IF_FAILED(Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().pDeviceComm->CompleteIo(&_WaitReplyMessage.Complete));
|
||||
// This call fails when the server pipe is closed on us,
|
||||
// which results in log spam in practice.
|
||||
std::ignore = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().pDeviceComm->CompleteIo(&_WaitReplyMessage.Complete);
|
||||
|
||||
fRetVal = true;
|
||||
}
|
||||
|
||||
@@ -471,15 +471,22 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter
|
||||
// We catch it here and store the information for later retrieval.
|
||||
if (_deviceAttributes.load(std::memory_order_relaxed) == 0)
|
||||
{
|
||||
til::enumset<DeviceAttribute, uint64_t> attributes;
|
||||
til::enumset<DeviceAttribute, uint64_t> attributes{ DeviceAttribute::__some__ };
|
||||
|
||||
// The first parameter denotes the conformance level.
|
||||
if (parameters.at(0).value() >= 61)
|
||||
const auto len = parameters.size();
|
||||
if (len >= 2 && parameters.at(0).value() >= 61)
|
||||
{
|
||||
parameters.subspan(1).for_each([&](auto p) {
|
||||
attributes.set(static_cast<DeviceAttribute>(p));
|
||||
return true;
|
||||
});
|
||||
// NOTE: VTParameters::for_each will replace empty spans with a single default value.
|
||||
// This means we could not distinguish between no parameters and a single default parameter.
|
||||
for (size_t i = 1; i < len; i++)
|
||||
{
|
||||
const auto value = parameters.at(i).value();
|
||||
if (value > 0 && value < 64)
|
||||
{
|
||||
attributes.set(static_cast<DeviceAttribute>(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_deviceAttributes.fetch_or(attributes.bits(), std::memory_order_relaxed);
|
||||
|
||||
@@ -51,6 +51,10 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
|
||||
enum class DeviceAttribute : uint64_t
|
||||
{
|
||||
// Special value to indicate that InputStateMachineEngine::_deviceAttributes has been set.
|
||||
// 0 in this case means 1<<0 == 1, which in turn means that _deviceAttributes is non-zero.
|
||||
__some__ = 0,
|
||||
|
||||
Columns132 = 1,
|
||||
PrinterPort = 2,
|
||||
Sixel = 4,
|
||||
|
||||
Reference in New Issue
Block a user