mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Compare commits
42 Commits
main
...
v1.23.1113
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
684b91f5f1 | ||
|
|
f3527bedf2 | ||
|
|
e8a883fd41 | ||
|
|
42a0b133d3 | ||
|
|
89cb70f098 | ||
|
|
c37b848845 | ||
|
|
8771b985ae | ||
|
|
ca218d3d7a | ||
|
|
b2cf9d1bac | ||
|
|
840f9623e5 | ||
|
|
cf3bbf53e6 | ||
|
|
3ff08aea1f | ||
|
|
16b737f9f5 | ||
|
|
aceb042499 | ||
|
|
3e70851d82 | ||
|
|
97c6ecb5a6 | ||
|
|
17ea33c42e | ||
|
|
21e63adec5 | ||
|
|
a9db4e403f | ||
|
|
d20c217751 | ||
|
|
7600888118 | ||
|
|
4f8a3d1845 | ||
|
|
38783fa595 | ||
|
|
a0140ef644 | ||
|
|
490e2bfc06 | ||
|
|
c1cd6d3d1d | ||
|
|
d938f924bb | ||
|
|
e9520c02ea | ||
|
|
2060fd6b11 | ||
|
|
70996f35d0 | ||
|
|
a37dc26fd8 | ||
|
|
29e401f202 | ||
|
|
0d7e1293fa | ||
|
|
a72531014c | ||
|
|
2590ff1383 | ||
|
|
863cdd44f2 | ||
|
|
73721c7a90 | ||
|
|
deeba28fda | ||
|
|
b43e7b93ec | ||
|
|
c6e20e99d7 | ||
|
|
8b0fc20f83 | ||
|
|
77638840e4 |
1
.github/actions/spelling/allow/allow.txt
vendored
1
.github/actions/spelling/allow/allow.txt
vendored
@ -11,6 +11,7 @@ colorbrewer
|
||||
commandlines
|
||||
consvc
|
||||
copyable
|
||||
CText
|
||||
dalet
|
||||
dcs
|
||||
deselection
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MUXCustomBuildTasks" version="1.0.48" targetFramework="native" />
|
||||
<package id="Microsoft.Taef" version="10.93.240607003" targetFramework="native" />
|
||||
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
|
||||
<package id="Microsoft.Debugging.Tools.PdbStr" version="20220617.1556.0" targetFramework="native" />
|
||||
|
||||
13
dep/vcpkg-overlay-ports/fmt/fix-write-batch.patch
Normal file
13
dep/vcpkg-overlay-ports/fmt/fix-write-batch.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 88c12148..967b53dd 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -260,7 +260,7 @@ if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
join(netfxpath
|
||||
"C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\"
|
||||
".NETFramework\\v4.0")
|
||||
- file(WRITE run-msbuild.bat "
|
||||
+ file(WRITE "${CMAKE_BINARY_DIR}/run-msbuild.bat" "
|
||||
${MSBUILD_SETUP}
|
||||
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||
endif ()
|
||||
38
dep/vcpkg-overlay-ports/fmt/portfile.cmake
Normal file
38
dep/vcpkg-overlay-ports/fmt/portfile.cmake
Normal file
@ -0,0 +1,38 @@
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO fmtlib/fmt
|
||||
REF "${VERSION}"
|
||||
SHA512 573b7de1bd224b7b1b60d44808a843db35d4bc4634f72a9edcb52cf68e99ca66c744fd5d5c97b4336ba70b94abdabac5fc253b245d0d5cd8bbe2a096bf941e39
|
||||
HEAD_REF master
|
||||
PATCHES
|
||||
fix-write-batch.patch
|
||||
)
|
||||
|
||||
vcpkg_cmake_configure(
|
||||
SOURCE_PATH "${SOURCE_PATH}"
|
||||
OPTIONS
|
||||
-DFMT_CMAKE_DIR=share/fmt
|
||||
-DFMT_TEST=OFF
|
||||
-DFMT_DOC=OFF
|
||||
-DFMT_PEDANTIC=ON
|
||||
)
|
||||
|
||||
vcpkg_cmake_install()
|
||||
vcpkg_cmake_config_fixup()
|
||||
vcpkg_fixup_pkgconfig()
|
||||
vcpkg_copy_pdbs()
|
||||
|
||||
if(VCPKG_LIBRARY_LINKAGE STREQUAL dynamic)
|
||||
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/fmt/base.h"
|
||||
"defined(FMT_SHARED)"
|
||||
"1"
|
||||
)
|
||||
endif()
|
||||
|
||||
file(REMOVE_RECURSE
|
||||
"${CURRENT_PACKAGES_DIR}/debug/include"
|
||||
"${CURRENT_PACKAGES_DIR}/debug/share"
|
||||
)
|
||||
|
||||
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
|
||||
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
|
||||
8
dep/vcpkg-overlay-ports/fmt/usage
Normal file
8
dep/vcpkg-overlay-ports/fmt/usage
Normal file
@ -0,0 +1,8 @@
|
||||
The package fmt provides CMake targets:
|
||||
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
target_link_libraries(main PRIVATE fmt::fmt)
|
||||
|
||||
# Or use the header-only version
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
target_link_libraries(main PRIVATE fmt::fmt-header-only)
|
||||
17
dep/vcpkg-overlay-ports/fmt/vcpkg.json
Normal file
17
dep/vcpkg-overlay-ports/fmt/vcpkg.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "fmt",
|
||||
"version": "11.1.4",
|
||||
"description": "{fmt} is an open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.",
|
||||
"homepage": "https://github.com/fmtlib/fmt",
|
||||
"license": "MIT",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "vcpkg-cmake",
|
||||
"host": true
|
||||
},
|
||||
{
|
||||
"name": "vcpkg-cmake-config",
|
||||
"host": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -2480,11 +2480,6 @@
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"startOnUserLogin": {
|
||||
"default": false,
|
||||
"description": "When set to true, this enables the launch of Terminal at startup. Setting this to false will disable the startup task entry. If the Terminal startup task entry is disabled either by org policy or by user action this setting will have no effect.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"firstWindowPreference": {
|
||||
"default": "defaultProfile",
|
||||
"description": "Defines what behavior the terminal takes when it starts. \"defaultProfile\" will have the terminal launch with one tab of the default profile, and \"persistedWindowLayout\" will cause the terminal to save its layout on close and reload it on open.",
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
<supportedOn>
|
||||
<definitions>
|
||||
<definition name="SUPPORTED_WindowsTerminal_1_21" displayName="$(string.SUPPORTED_WindowsTerminal_1_21)" />
|
||||
<definition name="SUPPORTED_DefaultTerminalApplication" displayName="$(string.SUPPORTED_DefaultTerminalApplication)" />
|
||||
</definitions>
|
||||
</supportedOn>
|
||||
<categories>
|
||||
@ -24,5 +25,61 @@
|
||||
<multiText id="DisabledProfileSources" valueName="DisabledProfileSources" required="true" />
|
||||
</elements>
|
||||
</policy>
|
||||
<policy name="DefaultTerminalApplication" class="User" displayName="$(string.DefaultTerminalApplication)" explainText="$(string.DefaultTerminalApplicationText)" presentation="$(presentation.TermAppSelection)" key="Console\%%Startup">
|
||||
<parentCategory ref="WindowsTerminal" />
|
||||
<supportedOn ref="SUPPORTED_DefaultTerminalApplication" />
|
||||
<elements>
|
||||
<enum id="TermAppSelect" required="true" valueName="DelegationTerminal">
|
||||
<item displayName="$(string.TermAppAutomatic)">
|
||||
<value>
|
||||
<string>{00000000-0000-0000-0000-000000000000}</string>
|
||||
</value>
|
||||
<valueList>
|
||||
<item key="Console\%%Startup" valueName="DelegationConsole">
|
||||
<value>
|
||||
<string>{00000000-0000-0000-0000-000000000000}</string>
|
||||
</value>
|
||||
</item>
|
||||
</valueList>
|
||||
</item>
|
||||
<item displayName="$(string.TermAppConsoleHost)">
|
||||
<value>
|
||||
<string>{B23D10C0-E52E-411E-9D5B-C09FDF709C7D}</string>
|
||||
</value>
|
||||
<valueList>
|
||||
<item key="Console\%%Startup" valueName="DelegationConsole">
|
||||
<value>
|
||||
<string>{B23D10C0-E52E-411E-9D5B-C09FDF709C7D}</string>
|
||||
</value>
|
||||
</item>
|
||||
</valueList>
|
||||
</item>
|
||||
<item displayName="$(string.TermAppWindowsTerminal)">
|
||||
<value>
|
||||
<string>{E12CFF52-A866-4C77-9A90-F570A7AA2C6B}</string>
|
||||
</value>
|
||||
<valueList>
|
||||
<item key="Console\%%Startup" valueName="DelegationConsole">
|
||||
<value>
|
||||
<string>{2EACA947-7F5F-4CFA-BA87-8F7FBEEFBE69}</string>
|
||||
</value>
|
||||
</item>
|
||||
</valueList>
|
||||
</item>
|
||||
<item displayName="$(string.TermAppWindowsTerminalPreview)">
|
||||
<value>
|
||||
<string>{86633F1F-6454-40EC-89CE-DA4EBA977EE2}</string>
|
||||
</value>
|
||||
<valueList>
|
||||
<item key="Console\%%Startup" valueName="DelegationConsole">
|
||||
<value>
|
||||
<string>{06EC847C-C0A5-46B8-92CB-7C92F6E35CD5}</string>
|
||||
</value>
|
||||
</item>
|
||||
</valueList>
|
||||
</item>
|
||||
</enum>
|
||||
</elements>
|
||||
</policy>
|
||||
</policies>
|
||||
</policyDefinitions>
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
<stringTable>
|
||||
<string id="WindowsTerminal">Windows Terminal</string>
|
||||
<string id="SUPPORTED_WindowsTerminal_1_21">At least Windows Terminal 1.21</string>
|
||||
<string id="SUPPORTED_DefaultTerminalApplication">At least Windows 11 22H2 or Windows 10 22H2 (Build 19045.3031, KB5026435) with Windows Terminal 1.17</string>
|
||||
<string id="DisabledProfileSources">Disabled Profile Sources</string>
|
||||
<string id="DisabledProfileSourcesText">Profiles will not be generated from any sources listed here. Source names can be arbitrary strings. Potential candidates can be found as the "source" property on profile definitions in Windows Terminal's settings.json file.
|
||||
|
||||
@ -18,11 +19,22 @@ Common sources are:
|
||||
For instance, setting this policy to Windows.Terminal.Wsl will disable the builtin WSL integration of Windows Terminal.
|
||||
|
||||
Note: Existing profiles will disappear from Windows Terminal after adding their source to this policy.</string>
|
||||
<string id="DefaultTerminalApplication">Default terminal application</string>
|
||||
<string id="DefaultTerminalApplicationText">Select the default terminal application used in Windows.
|
||||
|
||||
If you select Windows Terminal Preview and it is not installed the system will fallback to the legacy Windows Console Host. (Please note that the settings interfaces showing "Let windows decide" in this case as configuration.)</string>
|
||||
<string id="TermAppAutomatic">Automatic selection (Windows Terminal, if available)</string>
|
||||
<string id="TermAppConsoleHost">Windows Console Host (legacy)</string>
|
||||
<string id="TermAppWindowsTerminal">Windows Terminal</string>
|
||||
<string id="TermAppWindowsTerminalPreview">Windows Terminal Preview (if available)</string>
|
||||
</stringTable>
|
||||
<presentationTable>
|
||||
<presentation id="DisabledProfileSources">
|
||||
<multiTextBox refId="DisabledProfileSources">List of disabled sources (one per line)</multiTextBox>
|
||||
</presentation>
|
||||
<presentation id="TermAppSelection">
|
||||
<dropdownList refId="TermAppSelect" noSort="true" defaultItem="0">Select from the following options:</dropdownList>
|
||||
</presentation>
|
||||
</presentationTable>
|
||||
</resources>
|
||||
</policyDefinitionResources>
|
||||
|
||||
@ -431,7 +431,7 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType c
|
||||
THROW_HR_IF(E_INVALIDARG, limitRight.value_or(0) >= size());
|
||||
|
||||
// If we're given a right-side column limit, use it. Otherwise, the write limit is the final column index available in the char row.
|
||||
const auto finalColumnInRow = limitRight.value_or(size() - 1);
|
||||
const auto finalColumnInRow = gsl::narrow_cast<uint16_t>(limitRight.value_or(size() - 1));
|
||||
|
||||
auto currentColor = it->TextAttr();
|
||||
uint16_t colorUses = 0;
|
||||
|
||||
@ -2061,14 +2061,6 @@ void TextBuffer::_ExpandTextRow(til::inclusive_rect& textRow) const
|
||||
}
|
||||
}
|
||||
|
||||
size_t TextBuffer::SpanLength(const til::point coordStart, const til::point coordEnd) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
// The coords are inclusive, so to get the (inclusive) length we add 1.
|
||||
const auto length = bufferSize.CompareInBounds(coordEnd, coordStart) + 1;
|
||||
return gsl::narrow<size_t>(length);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Retrieves the plain text data between the specified coordinates.
|
||||
// Arguments:
|
||||
|
||||
@ -199,8 +199,6 @@ public:
|
||||
std::wstring GetCustomIdFromId(uint16_t id) const;
|
||||
void CopyHyperlinkMaps(const TextBuffer& OtherBuffer);
|
||||
|
||||
size_t SpanLength(const til::point coordStart, const til::point coordEnd) const;
|
||||
|
||||
std::wstring GetPlainText(til::point start, til::point end) const;
|
||||
|
||||
struct CopyRequest
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,8 +81,6 @@ static winrt::hstring _GetErrorText(SettingsLoadErrors error)
|
||||
return _GetMessageText(static_cast<uint32_t>(error), settingsLoadErrorsLabels);
|
||||
}
|
||||
|
||||
static constexpr std::wstring_view StartupTaskName = L"StartTerminalOnLoginTask";
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Function Description:
|
||||
@ -184,8 +182,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// this as a MTA, before the app is Create()'d
|
||||
WINRT_ASSERT(_loadedInitialSettings);
|
||||
|
||||
_ApplyLanguageSettingChange();
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"AppCreated",
|
||||
@ -335,8 +331,16 @@ namespace winrt::TerminalApp::implementation
|
||||
void AppLogic::_ApplyLanguageSettingChange() noexcept
|
||||
try
|
||||
{
|
||||
const auto language = _settings.GlobalSettings().Language();
|
||||
|
||||
if (!IsPackaged())
|
||||
{
|
||||
if (!language.empty())
|
||||
{
|
||||
// We cannot use the packaged app API, PrimaryLanguageOverride, but we *can* tell the resource loader
|
||||
// to set the Language for all loaded resources to the user's preferred language.
|
||||
winrt::Windows::ApplicationModel::Resources::Core::ResourceContext::SetGlobalQualifierValue(L"Language", language);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -344,8 +348,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
|
||||
const auto primaryLanguageOverride = ApplicationLanguages::PrimaryLanguageOverride();
|
||||
const auto language = _settings.GlobalSettings().Language();
|
||||
|
||||
if (primaryLanguageOverride != language)
|
||||
{
|
||||
ApplicationLanguages::PrimaryLanguageOverride(language);
|
||||
@ -353,40 +355,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
safe_void_coroutine AppLogic::_ApplyStartupTaskStateChange()
|
||||
try
|
||||
{
|
||||
// First, make sure we're running in a packaged context. This method
|
||||
// won't work, and will crash mysteriously if we're running unpackaged.
|
||||
if (!IsPackaged())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
const auto tryEnableStartupTask = _settings.GlobalSettings().StartOnUserLogin();
|
||||
const auto task = co_await StartupTask::GetAsync(StartupTaskName);
|
||||
|
||||
switch (task.State())
|
||||
{
|
||||
case StartupTaskState::Disabled:
|
||||
if (tryEnableStartupTask)
|
||||
{
|
||||
co_await task.RequestEnableAsync();
|
||||
}
|
||||
break;
|
||||
case StartupTaskState::DisabledByUser:
|
||||
// TODO: GH#6254: define UX for other StartupTaskStates
|
||||
break;
|
||||
case StartupTaskState::Enabled:
|
||||
if (!tryEnableStartupTask)
|
||||
{
|
||||
task.Disable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// Method Description:
|
||||
// - Reloads the settings from the settings.json file.
|
||||
// - When this is called the first time, this initializes our settings. See
|
||||
@ -435,6 +403,9 @@ namespace winrt::TerminalApp::implementation
|
||||
_settings.LogSettingChanges(true);
|
||||
}
|
||||
|
||||
_ApplyLanguageSettingChange();
|
||||
_ProcessLazySettingsChanges();
|
||||
|
||||
if (initialLoad)
|
||||
{
|
||||
// Register for directory change notification.
|
||||
@ -445,10 +416,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)
|
||||
{
|
||||
@ -473,7 +440,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// Both LoadSettings and ReloadSettings are supposed to call this function,
|
||||
// but LoadSettings skips it, so that the UI starts up faster.
|
||||
// Now that the UI is present we can do them with a less significant UX impact.
|
||||
_ApplyStartupTaskStateChange();
|
||||
_ProcessLazySettingsChanges();
|
||||
|
||||
FILETIME creationTime, exitTime, kernelTime, userTime, now;
|
||||
|
||||
@ -76,7 +76,6 @@ namespace winrt::TerminalApp::implementation
|
||||
TerminalApp::ContentManager _contentManager{ winrt::make<implementation::ContentManager>() };
|
||||
|
||||
void _ApplyLanguageSettingChange() noexcept;
|
||||
safe_void_coroutine _ApplyStartupTaskStateChange();
|
||||
|
||||
[[nodiscard]] HRESULT _TryLoadSettings() noexcept;
|
||||
void _ProcessLazySettingsChanges();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -60,9 +60,12 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
|
||||
DebugTapConnection::DebugTapConnection(ITerminalConnection wrappedConnection)
|
||||
{
|
||||
_outputRevoker = wrappedConnection.TerminalOutput(winrt::auto_revoke, { this, &DebugTapConnection::_OutputHandler });
|
||||
_stateChangedRevoker = wrappedConnection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*e*/) {
|
||||
StateChanged.raise(*this, nullptr);
|
||||
_outputRevoker = wrappedConnection.TerminalOutput(winrt::auto_revoke, { get_weak(), &DebugTapConnection::_OutputHandler });
|
||||
_stateChangedRevoker = wrappedConnection.StateChanged(winrt::auto_revoke, [weak = get_weak()](auto&& /*s*/, auto&& /*e*/) {
|
||||
if (const auto self = weak.get())
|
||||
{
|
||||
self->StateChanged.raise(*self, nullptr);
|
||||
}
|
||||
});
|
||||
_wrappedConnection = wrappedConnection;
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
CommandlineArgs::CommandlineArgs(winrt::array_view<const winrt::hstring> args, winrt::hstring currentDirectory, uint32_t showWindowCommand, winrt::hstring envString) :
|
||||
_args{ args.begin(), args.end() },
|
||||
_cwd{ std::move(currentDirectory) },
|
||||
CurrentDirectory{ std::move(currentDirectory) },
|
||||
ShowWindowCommand{ showWindowCommand },
|
||||
CurrentEnvironment{ std::move(envString) }
|
||||
{
|
||||
|
||||
@ -36,7 +36,6 @@ namespace winrt::TerminalApp::implementation
|
||||
::TerminalApp::AppCommandlineArgs _parsed;
|
||||
int32_t _parseResult = 0;
|
||||
winrt::com_array<winrt::hstring> _args;
|
||||
winrt::hstring _cwd;
|
||||
};
|
||||
|
||||
struct RequestReceiveContentArgs : RequestReceiveContentArgsT<RequestReceiveContentArgs>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -230,6 +230,7 @@
|
||||
VerticalScrollMode="Enabled"
|
||||
Visibility="Visible">
|
||||
<TextBlock x:Name="_descriptionComment"
|
||||
Margin="0,0,20,0"
|
||||
IsTextSelectionEnabled="True"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</ScrollViewer>
|
||||
|
||||
@ -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,59 @@ 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);
|
||||
}
|
||||
});
|
||||
|
||||
if (cwd.empty())
|
||||
{
|
||||
// We didn't actually need to change the virtual CWD, so we don't
|
||||
// need to restore it
|
||||
restoreCwd.release();
|
||||
}
|
||||
else
|
||||
if (!cwd.empty())
|
||||
{
|
||||
_WindowProperties.VirtualWorkingDirectory(cwd);
|
||||
}
|
||||
|
||||
if (env.empty())
|
||||
{
|
||||
restoreEnv.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
_WindowProperties.VirtualEnvVars(env);
|
||||
}
|
||||
|
||||
if (auto page{ weakThis.get() })
|
||||
for (size_t i = 0; i < actions.size(); ++i)
|
||||
{
|
||||
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 +1761,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 +1972,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 +3648,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 };
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
|
||||
#include <winrt/Windows.ApplicationModel.Resources.Core.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Foundation.Metadata.h>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -428,6 +428,20 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
TerminalOutput.raise(L"\r\n");
|
||||
TerminalOutput.raise(badPathText);
|
||||
}
|
||||
// If the requested action requires elevation, display appropriate message
|
||||
else if (hr == HRESULT_FROM_WIN32(ERROR_ELEVATION_REQUIRED))
|
||||
{
|
||||
const auto elevationText = RS_(L"ElevationRequired");
|
||||
TerminalOutput.raise(L"\r\n");
|
||||
TerminalOutput.raise(elevationText);
|
||||
}
|
||||
// If the requested executable was not found, display appropriate message
|
||||
else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||||
{
|
||||
const auto fileNotFoundText = RS_(L"FileNotFound");
|
||||
TerminalOutput.raise(L"\r\n");
|
||||
TerminalOutput.raise(fileNotFoundText);
|
||||
}
|
||||
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
|
||||
@ -780,12 +794,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,
|
||||
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Sie können dieses Terminal jetzt mit STRG+D schließen oder zum Neustart die EINGABETASTE drücken.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[Fehler {0} beim Start von `{1}']</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Auf das Startverzeichnis „{0}“ konnte nicht zugegriffen werden</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Für den angeforderten Vorgang sind erhöhte Rechte erforderlich.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Die angegebene Datei wurde nicht gefunden.</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>You can now close this terminal with Ctrl+D, or press Enter to restart.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[error {0} when launching `{1}']</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Could not access starting directory "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>The requested operation requires elevation.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>The system cannot find the file specified.</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Ahora puede cerrar este terminal con Ctrl+D o presionar Entrar para reiniciar.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[error {0} al iniciar `{1}']</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>No se pudo obtener acceso al directorio inicial «{0}»</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>La operación solicitada requiere elevación.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>El sistema no puede encontrar el archivo especificado.</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Vous pouvez maintenant fermer ce terminal avec Ctrl+D, ou appuyez sur Entrée pour redémarrer.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[erreur {0} lors du lancement de `{1}']</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Le démarrage du répertoire n’est pas accessible «{0}»</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>L’opération demandée nécessite une élévation.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Le fichier spécifié est introuvable.</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>È ora possibile chiudere il terminale con CTRL+D oppure premere INVIO per riavviarlo.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[errore {0} durante l'avvio di `{1}']</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Non è possibile accedere alla directory di avvio "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Per l'operazione richiesta è necessaria l'elevazione dei privilegi.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Impossibile trovare il file specificato.</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>このターミナルを Ctrl+D で閉じるか、Enter キーを押して再起動できます。</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>['{1}' の起動時にエラー {0} が発生しました]</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>先頭のディレクトリ "{0}" にアクセスできませんでした</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>要求された操作には、権限の昇格が必要です。</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>指定されたファイルが見つかりません。</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>이제 Ctrl+D 이 터미널을 닫거나 Enter 키를 눌러 다시 시작할 수 있습니다.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[’{1}' 시작 시 {0} 오류 발생]</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>시작 디렉터리 "{0}"에 액세스할 수 없습니다.</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>요청한 작업을 수행하려면 권한 상승이 필요합니다.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>시스템에서 지정된 파일을 찾을 수 없습니다.</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Agora você pode fechar este terminal com Ctrl+D ou pressione Enter para reiniciar.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[erro {0} ao iniciar "{1}"]</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Não foi possível acessar o diretório inicial "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>A operação solicitada exige elevação.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>O sistema não pode encontrar o arquivo especificado.</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Ỳóŭ ćǻή иòω сĺøѕè ťнįş тёѓмîήªŀ ωīťђ Çťѓℓ+Ď, όг ргéšѕ Σñтèř το ґèšтªят. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[℮ѓѓŏŕ {0} ωĥєй łåύñćђίηğ `{1}'] !!! !!! !!! </value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Ċőŭľđ йōť ª¢čеѕş şτāŗťΐиğ ðιѓεςтоŗγ "{0}" !!! !!! !!! !!!</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Ţнė ŗēqμĕѕŧєđ ôφ℮ґάтĩöй ŕєqΰїŗęś ėĺęνáτîøŋ. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Ŧнё şγśţêм ςâлηόť ƒїлď ŧнэ ƒΐĺë śрéćιƒієð. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Ỳóŭ ćǻή иòω сĺøѕè ťнįş тёѓмîήªŀ ωīťђ Çťѓℓ+Ď, όг ргéšѕ Σñтèř το ґèšтªят. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[℮ѓѓŏŕ {0} ωĥєй łåύñćђίηğ `{1}'] !!! !!! !!! </value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Ċőŭľđ йōť ª¢čеѕş şτāŗťΐиğ ðιѓεςтоŗγ "{0}" !!! !!! !!! !!!</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Ţнė ŗēqμĕѕŧєđ ôφ℮ґάтĩöй ŕєqΰїŗęś ėĺęνáτîøŋ. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Ŧнё şγśţêм ςâлηόť ƒїлď ŧнэ ƒΐĺë śрéćιƒієð. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Ỳóŭ ćǻή иòω сĺøѕè ťнįş тёѓмîήªŀ ωīťђ Çťѓℓ+Ď, όг ргéšѕ Σñтèř το ґèšтªят. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[℮ѓѓŏŕ {0} ωĥєй łåύñćђίηğ `{1}'] !!! !!! !!! </value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Ċőŭľđ йōť ª¢čеѕş şτāŗťΐиğ ðιѓεςтоŗγ "{0}" !!! !!! !!! !!!</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Ţнė ŗēqμĕѕŧєđ ôφ℮ґάтĩöй ŕєqΰїŗęś ėĺęνáτîøŋ. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Ŧнё şγśţêм ςâлηόť ƒїлď ŧнэ ƒΐĺë śрéćιƒієð. !!! !!! !!! !!! </value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>Теперь вы можете закрыть этот терминал с помощью клавиш CTRL+D. Или нажмите клавишу ВВОД для перезапуска.</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[ошибка {0} при запуске "{1}"]</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>Не удалось получить доступ к запуску каталога "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>Запрошенная операция требует получения дополнительных прав.</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>Не удается найти указанный файл.</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>现在可以使用Ctrl+D关闭此终端,或按 Enter 重新启动。</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[出现错误 {0} (启动“{1}”时)]</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>无法访问启动目录“{0}”</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>请求的操作需要提升。</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>系统找不到指定的文件。</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -209,7 +209,7 @@
|
||||
</data>
|
||||
<data name="CtrlDToClose" xml:space="preserve">
|
||||
<value>您現在可以使用 Ctrl+D 關閉此終端機,或按 Enter 重新啟動。</value>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
<comment>"Ctrl+D" and "Enter" represent keys the user will press (control+D and Enter).</comment>
|
||||
</data>
|
||||
<data name="ProcessFailedToLaunch" xml:space="preserve">
|
||||
<value>[啟動 `{1}' 時發生錯誤 {0}]</value>
|
||||
@ -220,4 +220,10 @@
|
||||
<value>無法存取開始目錄 "{0}"</value>
|
||||
<comment>The first argument {0} is a path to a directory on the filesystem, as provided by the user.</comment>
|
||||
</data>
|
||||
<data name="ElevationRequired" xml:space="preserve">
|
||||
<value>要求的操作需要提高權限。</value>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>系統找不到指定的檔案。</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -142,23 +142,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
|
||||
// the UIA Engine to the renderer. This prevents us from signaling changes to the cursor or buffer.
|
||||
{
|
||||
// First create the render thread.
|
||||
// Then stash a local pointer to the render thread so we can initialize it and enable it
|
||||
// to paint itself *after* we hand off its ownership to the renderer.
|
||||
// We split up construction and initialization of the render thread object this way
|
||||
// because the renderer and render thread have circular references to each other.
|
||||
auto renderThread = std::make_unique<::Microsoft::Console::Render::RenderThread>();
|
||||
auto* const localPointerToThread = renderThread.get();
|
||||
|
||||
// Now create the renderer and initialize the render thread.
|
||||
const auto& renderSettings = _terminal->GetRenderSettings();
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _terminal.get(), nullptr, 0, std::move(renderThread));
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _terminal.get());
|
||||
|
||||
_renderer->SetBackgroundColorChangedCallback([this]() { _rendererBackgroundColorChanged(); });
|
||||
_renderer->SetFrameColorChangedCallback([this]() { _rendererTabColorChanged(); });
|
||||
_renderer->SetRendererEnteredErrorStateCallback([this]() { RendererEnteredErrorState.raise(nullptr, nullptr); });
|
||||
|
||||
THROW_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
}
|
||||
|
||||
UpdateSettings(settings, unfocusedAppearance);
|
||||
@ -186,7 +176,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// thread is a workaround for us to hit GH#12607 less often.
|
||||
shared->outputIdle = std::make_unique<til::debounced_func_trailing<>>(
|
||||
std::chrono::milliseconds{ 100 },
|
||||
[weakTerminal = std::weak_ptr{ _terminal }, weakThis = get_weak(), dispatcher = _dispatcher]() {
|
||||
[this, weakThis = get_weak(), dispatcher = _dispatcher]() {
|
||||
dispatcher.TryEnqueue(DispatcherQueuePriority::Normal, [weakThis]() {
|
||||
if (const auto self = weakThis.get(); self && !self->_IsClosing())
|
||||
{
|
||||
@ -194,22 +184,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
});
|
||||
|
||||
if (const auto t = weakTerminal.lock())
|
||||
{
|
||||
const auto lock = t->LockForWriting();
|
||||
t->UpdatePatternsUnderLock();
|
||||
}
|
||||
// We can't use a `weak_ptr` to `_terminal` here, because it takes significant
|
||||
// dependency on the lifetime of `this` (primarily on our `_renderer`).
|
||||
// and a `weak_ptr` would allow it to outlive `this`.
|
||||
// Theoretically `debounced_func_trailing` should call `WaitForThreadpoolTimerCallbacks()`
|
||||
// with cancel=true on destruction, which should ensure that our use of `this` here is safe.
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
_terminal->UpdatePatternsUnderLock();
|
||||
});
|
||||
|
||||
// If you rapidly show/hide Windows Terminal, something about GotFocus()/LostFocus() gets broken.
|
||||
// We'll then receive easily 10+ such calls from WinUI the next time the application is shown.
|
||||
shared->focusChanged = std::make_unique<til::debounced_func_trailing<bool>>(
|
||||
std::chrono::milliseconds{ 25 },
|
||||
[weakThis = get_weak()](const bool focused) {
|
||||
if (const auto core{ weakThis.get() })
|
||||
{
|
||||
core->_focusChanged(focused);
|
||||
}
|
||||
[this](const bool focused) {
|
||||
// Theoretically `debounced_func_trailing` should call `WaitForThreadpoolTimerCallbacks()`
|
||||
// with cancel=true on destruction, which should ensure that our use of `this` here is safe.
|
||||
_focusChanged(focused);
|
||||
});
|
||||
|
||||
// Scrollbar updates are also expensive (XAML), so we'll throttle them as well.
|
||||
@ -224,19 +215,35 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
});
|
||||
}
|
||||
|
||||
// Safely disconnects event handlers from the connection and closes it. This is necessary because
|
||||
// WinRT event revokers don't prevent pending calls from proceeding (thread-safe but not race-free).
|
||||
void ControlCore::_closeConnection()
|
||||
{
|
||||
_connectionOutputEventRevoker.revoke();
|
||||
_connectionStateChangedRevoker.revoke();
|
||||
|
||||
// One of the tasks for `ITerminalConnection::Close()` is to block until all pending
|
||||
// callback calls have completed. This solves the race-condition issue mentioned above.
|
||||
if (_connection)
|
||||
{
|
||||
_connection.Close();
|
||||
_connection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ControlCore::~ControlCore()
|
||||
{
|
||||
Close();
|
||||
|
||||
_renderer.reset();
|
||||
_renderEngine.reset();
|
||||
// See notes about the _renderer member in the header file.
|
||||
_renderer->TriggerTeardown();
|
||||
}
|
||||
|
||||
void ControlCore::Detach()
|
||||
{
|
||||
// Disable the renderer, so that it doesn't try to start any new frames
|
||||
// for our engines while we're not attached to anything.
|
||||
_renderer->WaitForPaintCompletionAndDisable(INFINITE);
|
||||
_renderer->TriggerTeardown();
|
||||
|
||||
// Clear out any throttled funcs that we had wired up to run on this UI
|
||||
// thread. These will be recreated in _setupDispatcherAndCallbacks, when
|
||||
@ -276,8 +283,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto oldState = ConnectionState(); // rely on ControlCore's automatic null handling
|
||||
// revoke ALL old handlers immediately
|
||||
|
||||
_connectionOutputEventRevoker.revoke();
|
||||
_connectionStateChangedRevoker.revoke();
|
||||
_closeConnection();
|
||||
|
||||
_connection = newConnection;
|
||||
if (_connection)
|
||||
@ -366,7 +372,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
||||
const auto width = vp.Width();
|
||||
const auto height = vp.Height();
|
||||
_connection.Resize(height, width);
|
||||
|
||||
if (_connection)
|
||||
{
|
||||
_connection.Resize(height, width);
|
||||
}
|
||||
|
||||
if (_owningHwnd != 0)
|
||||
{
|
||||
@ -420,6 +430,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
if (_initializedTerminal.load(std::memory_order_relaxed))
|
||||
{
|
||||
// The lock must be held, because it calls into IRenderData which is shared state.
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
_renderer->EnablePainting();
|
||||
}
|
||||
@ -434,7 +445,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void ControlCore::_sendInputToConnection(std::wstring_view wstr)
|
||||
{
|
||||
_connection.WriteInput(winrt_wstring_to_array_view(wstr));
|
||||
if (_connection)
|
||||
{
|
||||
_connection.WriteInput(winrt_wstring_to_array_view(wstr));
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -471,7 +485,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const wchar_t CtrlD = 0x4;
|
||||
const wchar_t Enter = '\r';
|
||||
|
||||
if (_connection.State() >= winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::Closed)
|
||||
if (_connection && _connection.State() >= winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::Closed)
|
||||
{
|
||||
if (ch == CtrlD)
|
||||
{
|
||||
@ -1122,7 +1136,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
_connection.Resize(vp.Height(), vp.Width());
|
||||
if (_connection)
|
||||
{
|
||||
_connection.Resize(vp.Height(), vp.Width());
|
||||
}
|
||||
|
||||
// TermControl will call Search() once the OutputIdle even fires after 100ms.
|
||||
// Until then we need to hide the now-stale search results from the renderer.
|
||||
@ -1794,12 +1811,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
// Ensure Close() doesn't hang, waiting for MidiAudio to finish playing an hour long song.
|
||||
_midiAudio.BeginSkip();
|
||||
|
||||
// Stop accepting new output and state changes before we disconnect everything.
|
||||
_connectionOutputEventRevoker.revoke();
|
||||
_connectionStateChangedRevoker.revoke();
|
||||
_connection.Close();
|
||||
}
|
||||
|
||||
_closeConnection();
|
||||
}
|
||||
|
||||
void ControlCore::PersistToPath(const wchar_t* path) const
|
||||
@ -1817,9 +1831,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
FILETIME lastWriteTime;
|
||||
FILETIME localFileTime;
|
||||
SYSTEMTIME lastWriteSystemTime;
|
||||
if (!GetFileTime(file.get(), nullptr, nullptr, &lastWriteTime) ||
|
||||
!FileTimeToSystemTime(&lastWriteTime, &lastWriteSystemTime))
|
||||
|
||||
// Get the last write time in UTC
|
||||
if (!GetFileTime(file.get(), nullptr, nullptr, &lastWriteTime))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert UTC FILETIME to local FILETIME
|
||||
if (!FileTimeToLocalFileTime(&lastWriteTime, &localFileTime))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert local FILETIME to SYSTEMTIME
|
||||
if (!FileTimeToSystemTime(&localFileTime, &lastWriteSystemTime))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1896,7 +1924,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
const auto weakThis{ get_weak() };
|
||||
|
||||
// Concurrent read of _dispatcher is safe, because Detach() calls WaitForPaintCompletionAndDisable()
|
||||
// Concurrent read of _dispatcher is safe, because Detach() calls TriggerTeardown()
|
||||
// which blocks until this call returns. _dispatcher will only be changed afterwards.
|
||||
co_await wil::resume_foreground(_dispatcher);
|
||||
|
||||
@ -1947,8 +1975,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ControlCore::ResumeRendering()
|
||||
{
|
||||
// The lock must be held, because it calls into IRenderData which is shared state.
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
_renderer->ResetErrorStateAndResume();
|
||||
_renderer->EnablePainting();
|
||||
}
|
||||
|
||||
bool ControlCore::IsVtMouseModeEnabled() const
|
||||
@ -2839,6 +2868,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// coloring other matches, then we need to make sure those get redrawn,
|
||||
// too.
|
||||
_renderer->TriggerRedrawAll();
|
||||
_updateSelectionUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,65 +311,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> updateScrollBar;
|
||||
};
|
||||
|
||||
std::atomic<bool> _initializedTerminal{ false };
|
||||
bool _closing{ false };
|
||||
|
||||
TerminalConnection::ITerminalConnection _connection{ nullptr };
|
||||
TerminalConnection::ITerminalConnection::TerminalOutput_revoker _connectionOutputEventRevoker;
|
||||
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;
|
||||
|
||||
winrt::com_ptr<ControlSettings> _settings{ nullptr };
|
||||
|
||||
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
|
||||
std::wstring _pendingResponses;
|
||||
|
||||
// NOTE: _renderEngine must be ordered before _renderer.
|
||||
//
|
||||
// As _renderer has a dependency on _renderEngine (through a raw pointer)
|
||||
// we must ensure the _renderer is deallocated first.
|
||||
// (C++ class members are destroyed in reverse order.)
|
||||
std::unique_ptr<::Microsoft::Console::Render::Atlas::AtlasEngine> _renderEngine{ nullptr };
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr };
|
||||
|
||||
::Search _searcher;
|
||||
bool _snapSearchResultToSelection;
|
||||
|
||||
winrt::handle _lastSwapChainHandle{ nullptr };
|
||||
|
||||
FontInfoDesired _desiredFont;
|
||||
FontInfo _actualFont;
|
||||
bool _builtinGlyphs = true;
|
||||
bool _colorGlyphs = true;
|
||||
CSSLengthPercentage _cellWidth;
|
||||
CSSLengthPercentage _cellHeight;
|
||||
|
||||
// storage location for the leading surrogate of a utf-16 surrogate pair
|
||||
std::optional<wchar_t> _leadingSurrogate{ std::nullopt };
|
||||
|
||||
std::optional<til::point> _lastHoveredCell{ std::nullopt };
|
||||
// Track the last hyperlink ID we hovered over
|
||||
uint16_t _lastHoveredId{ 0 };
|
||||
|
||||
bool _isReadOnly{ false };
|
||||
|
||||
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> _lastHoveredInterval{ std::nullopt };
|
||||
|
||||
// These members represent the size of the surface that we should be
|
||||
// rendering to.
|
||||
float _panelWidth{ 0 };
|
||||
float _panelHeight{ 0 };
|
||||
float _compositionScale{ 0 };
|
||||
|
||||
uint64_t _owningHwnd{ 0 };
|
||||
|
||||
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
|
||||
til::shared_mutex<SharedState> _shared;
|
||||
|
||||
til::point _contextMenuBufferPosition{ 0, 0 };
|
||||
|
||||
Windows::Foundation::Collections::IVector<hstring> _cachedQuickFixes{ nullptr };
|
||||
|
||||
void _setupDispatcherAndCallbacks();
|
||||
void _closeConnection();
|
||||
|
||||
bool _setFontSizeUnderLock(float fontSize);
|
||||
void _updateFont();
|
||||
@ -396,12 +339,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _terminalWindowSizeChanged(int32_t width, int32_t height);
|
||||
|
||||
safe_void_coroutine _terminalCompletionsChanged(std::wstring_view menuJson, unsigned int replaceLength);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
MidiAudio _midiAudio;
|
||||
winrt::Windows::System::DispatcherQueueTimer _midiAudioSkipTimer{ nullptr };
|
||||
|
||||
#pragma region RendererCallbacks
|
||||
void _rendererWarning(const HRESULT hr, wil::zwstring_view parameter);
|
||||
safe_void_coroutine _renderEngineSwapChainChanged(const HANDLE handle);
|
||||
@ -412,6 +351,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _raiseReadOnlyWarning();
|
||||
void _updateAntiAliasingMode();
|
||||
void _connectionOutputHandler(const hstring& hstr);
|
||||
void _connectionStateChangedHandler(const TerminalConnection::ITerminalConnection&, const Windows::Foundation::IInspectable&);
|
||||
void _updateHoveredCell(const std::optional<til::point> terminalPosition);
|
||||
void _setOpacity(const float opacity, const bool focused = true);
|
||||
|
||||
@ -443,6 +383,70 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _closing;
|
||||
}
|
||||
|
||||
// Caches responses generated by our VT parser (= improved batching).
|
||||
std::wstring _pendingResponses;
|
||||
|
||||
// Font stuff.
|
||||
FontInfoDesired _desiredFont;
|
||||
FontInfo _actualFont;
|
||||
bool _builtinGlyphs = true;
|
||||
bool _colorGlyphs = true;
|
||||
CSSLengthPercentage _cellWidth;
|
||||
CSSLengthPercentage _cellHeight;
|
||||
|
||||
// Rendering stuff.
|
||||
winrt::handle _lastSwapChainHandle{ nullptr };
|
||||
uint64_t _owningHwnd{ 0 };
|
||||
float _panelWidth{ 0 };
|
||||
float _panelHeight{ 0 };
|
||||
float _compositionScale{ 0 };
|
||||
|
||||
// Audio stuff.
|
||||
MidiAudio _midiAudio;
|
||||
winrt::Windows::System::DispatcherQueueTimer _midiAudioSkipTimer{ nullptr };
|
||||
|
||||
// Other stuff.
|
||||
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
|
||||
winrt::com_ptr<ControlSettings> _settings{ nullptr };
|
||||
til::point _contextMenuBufferPosition{ 0, 0 };
|
||||
Windows::Foundation::Collections::IVector<hstring> _cachedQuickFixes{ nullptr };
|
||||
::Search _searcher;
|
||||
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> _lastHoveredInterval;
|
||||
std::optional<wchar_t> _leadingSurrogate;
|
||||
std::optional<til::point> _lastHoveredCell;
|
||||
uint16_t _lastHoveredId{ 0 };
|
||||
std::atomic<bool> _initializedTerminal{ false };
|
||||
bool _isReadOnly{ false };
|
||||
bool _closing{ false };
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// These are ordered last to ensure they're destroyed first.
|
||||
// This ensures that their respective contents stops taking dependency on the above.
|
||||
// I recommend reading the following paragraphs in reverse order.
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
// ↑ This one is tricky - all of these are raw pointers:
|
||||
// 1. _terminal depends on _renderer (for invalidations)
|
||||
// 2. _renderer depends on _terminal (for IRenderData)
|
||||
// = circular dependency = architectural flaw (lifetime issues) = TODO
|
||||
// 3. _renderer depends on _renderEngine (AtlasEngine)
|
||||
// To solve the knot, we manually stop the renderer in the destructor,
|
||||
// which breaks 2. We can proceed then proceed to break 1. and then 3.
|
||||
std::unique_ptr<::Microsoft::Console::Render::Atlas::AtlasEngine> _renderEngine{ nullptr }; // 3.
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr }; // 3.
|
||||
std::shared_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr }; // 1.
|
||||
|
||||
// ↑ MOST IMPORTANTLY: `_outputIdle` takes dependency on the raw `this` pointer (necessarily).
|
||||
// Destroying SharedState here will block until all pending `debounced_func_trailing` calls are completed.
|
||||
til::shared_mutex<SharedState> _shared;
|
||||
|
||||
// ↑ Prevent any more unnecessary `_outputIdle` calls.
|
||||
// Technically none of these members are destroyed here. Instead, the destructor will call Close()
|
||||
// which calls _closeConnection() which in turn manually & safely destroys them in the correct order.
|
||||
TerminalConnection::ITerminalConnection::TerminalOutput_revoker _connectionOutputEventRevoker;
|
||||
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;
|
||||
TerminalConnection::ITerminalConnection _connection{ nullptr };
|
||||
|
||||
friend class ControlUnitTests::ControlCoreTests;
|
||||
friend class ControlUnitTests::ControlInteractivityTests;
|
||||
bool _inUnitTests{ false };
|
||||
|
||||
@ -73,7 +73,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
//
|
||||
// To alleviate, make sure to disable the UIA engine and remove it,
|
||||
// and ALSO disable the renderer. Core.Detach will take care of the
|
||||
// WaitForPaintCompletionAndDisable (which will stop the renderer
|
||||
// TriggerTeardown (which will stop the renderer
|
||||
// after all current engines are done painting).
|
||||
//
|
||||
// Simply disabling the UIA engine is not enough, because it's
|
||||
@ -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.
|
||||
//
|
||||
|
||||
@ -206,14 +206,10 @@ HRESULT HwndTerminal::Initialize()
|
||||
_terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>();
|
||||
const auto lock = _terminal->LockForWriting();
|
||||
|
||||
auto renderThread = std::make_unique<::Microsoft::Console::Render::RenderThread>();
|
||||
auto* const localPointerToThread = renderThread.get();
|
||||
auto& renderSettings = _terminal->GetRenderSettings();
|
||||
renderSettings.SetColorTableEntry(TextColor::DEFAULT_BACKGROUND, RGB(12, 12, 12));
|
||||
renderSettings.SetColorTableEntry(TextColor::DEFAULT_FOREGROUND, RGB(204, 204, 204));
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _terminal.get(), nullptr, 0, std::move(renderThread));
|
||||
RETURN_HR_IF_NULL(E_POINTER, localPointerToThread);
|
||||
RETURN_IF_FAILED(localPointerToThread->Initialize(_renderer.get()));
|
||||
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _terminal.get());
|
||||
|
||||
auto engine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
|
||||
RETURN_IF_FAILED(engine->SetHwnd(_hwnd.get()));
|
||||
@ -234,7 +230,7 @@ HRESULT HwndTerminal::Initialize()
|
||||
|
||||
_terminal->Create({ 80, 25 }, 9001, *_renderer);
|
||||
_terminal->SetWriteInputCallback([=](std::wstring_view input) noexcept { _WriteTextToConnection(input); });
|
||||
localPointerToThread->EnablePainting();
|
||||
_renderer->EnablePainting();
|
||||
|
||||
_multiClickTime = std::chrono::milliseconds{ GetDoubleClickTime() };
|
||||
|
||||
|
||||
@ -95,7 +95,7 @@
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>delayimp.lib;Uiautomationcore.lib;onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>uiautomationcore.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<DelayLoadDLLs>uiautomationcore.dll;icu.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<!--
|
||||
ControlLib contains a DllMain that we need to force the use of.
|
||||
If you don't have this, then you'll see an error like
|
||||
|
||||
@ -1571,10 +1571,10 @@ void Terminal::SerializeMainBuffer(const wchar_t* destination) const
|
||||
|
||||
void Terminal::ColorSelection(const TextAttribute& attr, winrt::Microsoft::Terminal::Core::MatchMode matchMode)
|
||||
{
|
||||
const auto colorSelection = [this](const til::point coordStart, const til::point coordEnd, const TextAttribute& attr) {
|
||||
const auto colorSelection = [this](const til::point coordStartInclusive, const til::point coordEndExclusive, const TextAttribute& attr) {
|
||||
auto& textBuffer = _activeBuffer();
|
||||
const auto spanLength = textBuffer.SpanLength(coordStart, coordEnd);
|
||||
textBuffer.Write(OutputCellIterator(attr, spanLength), coordStart);
|
||||
const auto spanLength = textBuffer.GetSize().CompareInBounds(coordEndExclusive, coordStartInclusive, true);
|
||||
textBuffer.Write(OutputCellIterator(attr, spanLength), coordStartInclusive);
|
||||
};
|
||||
|
||||
for (const auto [start, end] : _GetSelectionSpans())
|
||||
|
||||
@ -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=""
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "Launch.h"
|
||||
#include "Launch.g.cpp"
|
||||
#include "EnumEntry.h"
|
||||
#include "LaunchViewModel.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
|
||||
@ -40,5 +41,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void Launch::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::LaunchViewModel>();
|
||||
auto innerViewModel{ winrt::get_self<Editor::implementation::LaunchViewModel>(_ViewModel) };
|
||||
/* coroutine dispatch */ innerViewModel->PrepareStartOnUserLoginSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,8 +140,7 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Language -->
|
||||
<local:SettingContainer x:Uid="Globals_Language"
|
||||
Visibility="{x:Bind ViewModel.LanguageSelectorAvailable}">
|
||||
<local:SettingContainer x:Uid="Globals_Language">
|
||||
<ComboBox ItemsSource="{x:Bind ViewModel.LanguageList}"
|
||||
SelectedItem="{x:Bind ViewModel.CurrentLanguage, Mode=TwoWay}"
|
||||
Style="{StaticResource ComboBoxSettingStyle}">
|
||||
@ -163,8 +162,11 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Start on User Login -->
|
||||
<local:SettingContainer x:Uid="Globals_StartOnUserLogin">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.StartOnUserLogin, Mode=TwoWay}"
|
||||
<local:SettingContainer x:Uid="Globals_StartOnUserLogin"
|
||||
HelpText="{x:Bind ViewModel.StartOnUserLoginStatefulHelpText, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.StartOnUserLoginAvailable, Mode=OneTime}">
|
||||
<ToggleSwitch IsEnabled="{x:Bind ViewModel.StartOnUserLoginConfigurable, Mode=OneWay}"
|
||||
IsOn="{x:Bind ViewModel.StartOnUserLogin, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
|
||||
@ -14,6 +14,8 @@ using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Windows::UI::Xaml::Data;
|
||||
|
||||
static constexpr std::wstring_view StartupTaskName = L"StartTerminalOnLoginTask";
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
// For ComboBox an empty SelectedItem string denotes no selection.
|
||||
@ -80,16 +82,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return language.NativeName();
|
||||
}
|
||||
|
||||
// Returns whether the language selector is available/shown.
|
||||
//
|
||||
// winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride()
|
||||
// doesn't work for unpackaged applications. The corresponding code in TerminalApp is disabled.
|
||||
// It would be confusing for our users if we presented a dysfunctional language selector.
|
||||
bool LaunchViewModel::LanguageSelectorAvailable()
|
||||
{
|
||||
return IsPackaged();
|
||||
}
|
||||
|
||||
// Returns the list of languages the user may override the application language with.
|
||||
// The returned list are BCP 47 language tags like {"und", "en-US", "de-DE", "es-ES", ...}.
|
||||
// "und" is short for "undefined" and is synonymous for "Use system language" in this code.
|
||||
@ -100,12 +92,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return _languageList;
|
||||
}
|
||||
|
||||
if (!LanguageSelectorAvailable())
|
||||
{
|
||||
_languageList = {};
|
||||
return _languageList;
|
||||
}
|
||||
|
||||
// In order to return the language list this code does the following:
|
||||
// [1] Get all possible languages we want to allow the user to choose.
|
||||
// We have to acquire languages from multiple sources, creating duplicates. See below at [1].
|
||||
@ -177,19 +163,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return _currentLanguage;
|
||||
}
|
||||
|
||||
if (!LanguageSelectorAvailable())
|
||||
winrt::hstring currentLanguage;
|
||||
if (IsPackaged())
|
||||
{
|
||||
_currentLanguage = {};
|
||||
return _currentLanguage;
|
||||
// NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
|
||||
currentLanguage = winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_Settings.GlobalSettings().HasLanguage())
|
||||
{
|
||||
currentLanguage = _Settings.GlobalSettings().Language();
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
|
||||
auto currentLanguage = winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride();
|
||||
if (currentLanguage.empty())
|
||||
{
|
||||
currentLanguage = systemLanguageTag;
|
||||
}
|
||||
|
||||
_currentLanguage = winrt::box_value(currentLanguage);
|
||||
return _currentLanguage;
|
||||
}
|
||||
@ -365,4 +356,86 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
return _Settings.DefaultTerminals();
|
||||
}
|
||||
|
||||
bool LaunchViewModel::StartOnUserLoginAvailable()
|
||||
{
|
||||
return IsPackaged();
|
||||
}
|
||||
|
||||
safe_void_coroutine LaunchViewModel::PrepareStartOnUserLoginSettings()
|
||||
{
|
||||
if (!StartOnUserLoginAvailable())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto strongThis{ get_strong() };
|
||||
auto task{ co_await winrt::Windows::ApplicationModel::StartupTask::GetAsync(StartupTaskName) };
|
||||
_startOnUserLoginTask = std::move(task);
|
||||
_NotifyChanges(L"StartOnUserLoginConfigurable", L"StartOnUserLoginStatefulHelpText", L"StartOnUserLogin");
|
||||
}
|
||||
|
||||
bool LaunchViewModel::StartOnUserLoginConfigurable()
|
||||
{
|
||||
if (!_startOnUserLoginTask)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
namespace WAM = winrt::Windows::ApplicationModel;
|
||||
const auto state{ _startOnUserLoginTask.State() };
|
||||
// Terminal cannot change the state of the login task if it is any of the "ByUser" or "ByPolicy" states.
|
||||
return state == WAM::StartupTaskState::Disabled || state == WAM::StartupTaskState::Enabled;
|
||||
}
|
||||
|
||||
winrt::hstring LaunchViewModel::StartOnUserLoginStatefulHelpText()
|
||||
{
|
||||
if (_startOnUserLoginTask)
|
||||
{
|
||||
namespace WAM = winrt::Windows::ApplicationModel;
|
||||
switch (_startOnUserLoginTask.State())
|
||||
{
|
||||
case WAM::StartupTaskState::EnabledByPolicy:
|
||||
case WAM::StartupTaskState::DisabledByPolicy:
|
||||
return winrt::hstring{ L"\uE72E " } /*lock icon*/ + RS_(L"Globals_StartOnUserLogin_UnavailableByPolicy");
|
||||
case WAM::StartupTaskState::DisabledByUser:
|
||||
return RS_(L"Globals_StartOnUserLogin_DisabledByUser");
|
||||
case WAM::StartupTaskState::Enabled:
|
||||
case WAM::StartupTaskState::Disabled:
|
||||
default:
|
||||
break; // fall through to the common case (no task, not configured, etc.)
|
||||
}
|
||||
}
|
||||
return RS_(L"Globals_StartOnUserLogin/HelpText");
|
||||
}
|
||||
|
||||
bool LaunchViewModel::StartOnUserLogin()
|
||||
{
|
||||
if (!_startOnUserLoginTask)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
namespace WAM = winrt::Windows::ApplicationModel;
|
||||
const auto state{ _startOnUserLoginTask.State() };
|
||||
return state == WAM::StartupTaskState::Enabled || state == WAM::StartupTaskState::EnabledByPolicy;
|
||||
}
|
||||
|
||||
safe_void_coroutine LaunchViewModel::StartOnUserLogin(bool enable)
|
||||
{
|
||||
if (!_startOnUserLoginTask)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto strongThis{ get_strong() };
|
||||
if (enable)
|
||||
{
|
||||
co_await _startOnUserLoginTask.RequestEnableAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
_startOnUserLoginTask.Disable();
|
||||
}
|
||||
// Any of these could have changed in response to an attempt to enable (e.g. it was disabled in task manager since our last check)
|
||||
_NotifyChanges(L"StartOnUserLoginConfigurable", L"StartOnUserLoginStatefulHelpText", L"StartOnUserLogin");
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "LaunchViewModel.g.h"
|
||||
#include "ViewModelHelpers.h"
|
||||
#include "Utils.h"
|
||||
#include <cppwinrt_utils.h>
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
@ -19,7 +20,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// "Deutsch (Deutschland)". This works independently of the user's locale.
|
||||
static winrt::hstring LanguageDisplayConverter(const winrt::hstring& tag);
|
||||
|
||||
bool LanguageSelectorAvailable();
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> LanguageList();
|
||||
winrt::Windows::Foundation::IInspectable CurrentLanguage();
|
||||
void CurrentLanguage(const winrt::Windows::Foundation::IInspectable& tag);
|
||||
@ -51,10 +51,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
GETSET_BINDABLE_ENUM_SETTING(WindowingBehavior, Model::WindowingMode, _Settings.GlobalSettings().WindowingBehavior);
|
||||
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_Settings.GlobalSettings(), CenterOnLaunch);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_Settings.GlobalSettings(), StartOnUserLogin);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_Settings.GlobalSettings(), InitialRows);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_Settings.GlobalSettings(), InitialCols);
|
||||
|
||||
bool StartOnUserLoginAvailable();
|
||||
safe_void_coroutine PrepareStartOnUserLoginSettings();
|
||||
bool StartOnUserLoginConfigurable();
|
||||
winrt::hstring StartOnUserLoginStatefulHelpText();
|
||||
bool StartOnUserLogin();
|
||||
safe_void_coroutine StartOnUserLogin(bool enable);
|
||||
|
||||
private:
|
||||
Model::CascadiaSettings _Settings;
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> _languageList;
|
||||
@ -63,6 +69,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> _LaunchModeList;
|
||||
winrt::Windows::Foundation::Collections::IMap<Model::LaunchMode, winrt::Microsoft::Terminal::Settings::Editor::EnumEntry> _LaunchModeMap;
|
||||
|
||||
winrt::Windows::ApplicationModel::StartupTask _startOnUserLoginTask{ nullptr };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -9,10 +9,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass LaunchViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
LaunchViewModel(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
|
||||
|
||||
static String LanguageDisplayConverter(String tag);
|
||||
Boolean LanguageSelectorAvailable { get; };
|
||||
Windows.Foundation.Collections.IObservableVector<String> LanguageList { get; };
|
||||
IInspectable CurrentLanguage;
|
||||
|
||||
@ -41,8 +38,12 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> WindowingBehaviorList { get; };
|
||||
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, CenterOnLaunch);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, StartOnUserLogin);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Int32, InitialRows);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Int32, InitialCols);
|
||||
|
||||
Boolean StartOnUserLogin { get; set; };
|
||||
Boolean StartOnUserLoginAvailable { get; };
|
||||
Boolean StartOnUserLoginConfigurable { get; };
|
||||
String StartOnUserLoginStatefulHelpText { get; };
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
||||
static const std::wstring_view openJsonTag{ L"OpenJson_Nav" };
|
||||
static const std::wstring_view launchTag{ L"Launch_Nav" };
|
||||
static const std::wstring_view interactionTag{ L"Interaction_Nav" };
|
||||
static const std::wstring_view renderingTag{ L"Rendering_Nav" };
|
||||
@ -324,6 +325,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
if (const auto navString = clickedItemContainer.Tag().try_as<hstring>())
|
||||
{
|
||||
if (*navString == openJsonTag)
|
||||
{
|
||||
const auto window = CoreWindow::GetForCurrentThread();
|
||||
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
|
||||
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
|
||||
const auto altPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) ||
|
||||
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
|
||||
const auto target = altPressed ? SettingsTarget::DefaultsFile : SettingsTarget::SettingsFile;
|
||||
OpenJson.raise(nullptr, target);
|
||||
return;
|
||||
}
|
||||
_Navigate(*navString, BreadcrumbSubPage::None);
|
||||
}
|
||||
else if (const auto profile = clickedItemContainer.Tag().try_as<Editor::ProfileViewModel>())
|
||||
@ -575,27 +587,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::OpenJsonTapped(const IInspectable& /*sender*/, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& /*args*/)
|
||||
{
|
||||
const auto window = CoreWindow::GetForCurrentThread();
|
||||
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
|
||||
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
|
||||
const auto altPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) ||
|
||||
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
|
||||
|
||||
const auto target = altPressed ? SettingsTarget::DefaultsFile : SettingsTarget::SettingsFile;
|
||||
OpenJson.raise(nullptr, target);
|
||||
}
|
||||
|
||||
void MainPage::OpenJsonKeyDown(const IInspectable& /*sender*/, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& args)
|
||||
{
|
||||
if (args.Key() == VirtualKey::Enter || args.Key() == VirtualKey::Space)
|
||||
{
|
||||
const auto target = args.KeyStatus().IsMenuKeyDown ? SettingsTarget::DefaultsFile : SettingsTarget::SettingsFile;
|
||||
OpenJson.raise(nullptr, target);
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::SaveButton_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
_settingsClone.LogSettingChanges(false);
|
||||
|
||||
@ -30,8 +30,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void UpdateSettings(const Model::CascadiaSettings& settings);
|
||||
|
||||
void OpenJsonKeyDown(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& args);
|
||||
void OpenJsonTapped(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& args);
|
||||
void SettingsNav_Loaded(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void SettingsNav_ItemInvoked(const Microsoft::UI::Xaml::Controls::NavigationView& sender, const Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs& args);
|
||||
void SaveButton_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
|
||||
@ -171,8 +171,8 @@
|
||||
<!-- The OpenJson item needs both Tapped and KeyDown handler -->
|
||||
<muxc:NavigationViewItem x:Name="OpenJsonNavItem"
|
||||
x:Uid="Nav_OpenJSON"
|
||||
KeyDown="OpenJsonKeyDown"
|
||||
Tapped="OpenJsonTapped">
|
||||
SelectsOnInvoked="False"
|
||||
Tag="OpenJson_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>Keine</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Der automatische Start wurde im Abschnitt "Start-Apps" der einstellungen für Windows deaktiviert.</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Diese Option wird durch eine Unternehmensrichtlinie verwaltet und kann hier nicht geändert werden.</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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">
|
||||
@ -2332,4 +2332,12 @@
|
||||
<value>None</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Automatic startup has been disabled in the Startup Apps section of Windows settings.</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>This option is managed by enterprise policy and cannot be changed here.</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>Ninguno</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Se ha deshabilitado el inicio automático en la sección Aplicaciones de inicio de Windows configuración.</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Esta opción está administrada por una directiva de empresa y no se puede cambiar aquí.</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>Aucun</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Le démarrage automatique a été désactivé dans la section Applications de démarrage de Windows paramètres.</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Cette option est gérée par la stratégie d’entreprise et ne peut pas être modifiée ici.</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>Nessuno</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>L'avvio automatico è stato disabilitato nella sezione App di avvio delle impostazioni Windows.</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Questa opzione è gestita da criteri aziendali e non può essere modificata qui.</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>なし</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Windows 設定の [スタートアップ アプリ] セクションで、自動スタートアップが無効になっています。</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>このオプションはエンタープライズ ポリシーによって管理されているため、ここで変更することはできません。</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2304,6 +2312,10 @@
|
||||
<value>MSYS2(C:\ -> /c)</value>
|
||||
<comment>{Locked="MSYS2","C:\","/c"} An option to choose from for the "path translation" setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyleMinGW.Content" xml:space="preserve">
|
||||
<value>MinGW(C:\ -> C:/)</value>
|
||||
<comment>{Locked="MinGW","C:\","C:/"} An option to choose from for the "path translation" setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_Delete_Orphaned.Header" xml:space="preserve">
|
||||
<value>프로필이 더 이상 검색되지 않음</value>
|
||||
</data>
|
||||
@ -2320,4 +2332,12 @@
|
||||
<value>없음</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Windows 설정의 Startup Apps 섹션에서 자동 시작을 사용하지 않도록 설정했습니다.</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>이 옵션은 엔터프라이즈 정책에 의해 관리되므로 여기에서 변경할 수 없습니다.</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>Nenhum</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>A inicialização automática foi desabilitada na seção Aplicativos de Inicialização Windows configurações.</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Esta opção é gerenciada pela política corporativa e não pode ser alterada aqui.</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2324,4 +2332,12 @@
|
||||
<value>Ŋøиє !</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Åΰťόмåтίĉ śţдѓтΰρ ћăş ьěёή δіѕªъľēð ïй ťĥ℮ Ŝťǻřťúφ Āρφŝ ѕěĉŧϊōη бƒ Windows ŝεтţīŋĝś. !!! !!! !!! !!! !!! !!! !!! !!! !</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Ţĥîŝ όρтįοñ íş мαпªģéð ъý ĕŋτéřрŗĭšз рôľĩсу алð çąňηōт ье ċħâήğèď ћēяē. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2324,4 +2332,12 @@
|
||||
<value>Ŋøиє !</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Åΰťόмåтίĉ śţдѓтΰρ ћăş ьěёή δіѕªъľēð ïй ťĥ℮ Ŝťǻřťúφ Āρφŝ ѕěĉŧϊōη бƒ Windows ŝεтţīŋĝś. !!! !!! !!! !!! !!! !!! !!! !!! !</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Ţĥîŝ όρтįοñ íş мαпªģéð ъý ĕŋτéřрŗĭšз рôľĩсу алð çąňηōт ье ċħâήğèď ћēяē. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2324,4 +2332,12 @@
|
||||
<value>Ŋøиє !</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Åΰťόмåтίĉ śţдѓтΰρ ћăş ьěёή δіѕªъľēð ïй ťĥ℮ Ŝťǻřťúφ Āρφŝ ѕěĉŧϊōη бƒ Windows ŝεтţīŋĝś. !!! !!! !!! !!! !!! !!! !!! !!! !</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Ţĥîŝ όρтįοñ íş мαпªģéð ъý ĕŋτéřрŗĭšз рôľĩсу алð çąňηōт ье ċħâήğèď ћēяē. !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>Нет</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>Автоматическая загрузка отключена в разделе "Приложения запуска" Windows параметрах.</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>Этот параметр управляется политикой предприятия и не может быть изменен здесь.</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>无</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>已在 Windows 设置的“启动应用”部分禁用自动启动。</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>此选项由企业策略管理,无法在此处更改。</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -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>
|
||||
@ -2320,4 +2328,12 @@
|
||||
<value>無</value>
|
||||
<comment>Text displayed when the tab title is not defined.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_DisabledByUser" xml:space="preserve">
|
||||
<value>已在 Windows 設定的 [啟動應用程式] 區段中停用自動啟動。</value>
|
||||
<comment>{Locked="Windows"}This is displayed in concordance with Globals_StartOnUserLogin if the user has disabled the setting outside of the application.</comment>
|
||||
</data>
|
||||
<data name="Globals_StartOnUserLogin_UnavailableByPolicy" xml:space="preserve">
|
||||
<value>此選項由企業原則管理,無法在此變更。</value>
|
||||
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@ -46,7 +46,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
L"HelpText",
|
||||
xaml_typename<hstring>(),
|
||||
xaml_typename<Editor::SettingContainer>(),
|
||||
PropertyMetadata{ box_value(L"") });
|
||||
PropertyMetadata{ box_value(L""), PropertyChangedCallback{ &SettingContainer::_OnHelpTextChanged } });
|
||||
}
|
||||
if (!_FontIconGlyphProperty)
|
||||
{
|
||||
@ -126,48 +126,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
get_self<SettingContainer>(obj)->_UpdateOverrideSystem();
|
||||
}
|
||||
|
||||
void SettingContainer::OnApplyTemplate()
|
||||
void SettingContainer::_OnHelpTextChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*args*/)
|
||||
{
|
||||
if (const auto& child{ GetTemplateChild(L"ResetButton") })
|
||||
{
|
||||
if (const auto& button{ child.try_as<Controls::Button>() })
|
||||
{
|
||||
// Apply click handler for the reset button.
|
||||
// When clicked, we dispatch the bound ClearSettingValue event,
|
||||
// resulting in inheriting the setting value from the parent.
|
||||
button.Click([=](auto&&, auto&&) {
|
||||
ClearSettingValue.raise(*this, nullptr);
|
||||
|
||||
// move the focus to the child control
|
||||
if (const auto& content{ Content() })
|
||||
{
|
||||
if (const auto& control{ content.try_as<Controls::Control>() })
|
||||
{
|
||||
control.Focus(FocusState::Programmatic);
|
||||
return;
|
||||
}
|
||||
else if (const auto& panel{ content.try_as<Controls::Panel>() })
|
||||
{
|
||||
for (const auto& panelChild : panel.Children())
|
||||
{
|
||||
if (const auto& panelControl{ panelChild.try_as<Controls::Control>() })
|
||||
{
|
||||
panelControl.Focus(FocusState::Programmatic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we get here, we didn't find something to reasonably focus to.
|
||||
}
|
||||
});
|
||||
|
||||
// apply name (automation property)
|
||||
Automation::AutomationProperties::SetName(child, RS_(L"SettingContainer_OverrideMessageBaseLayer"));
|
||||
}
|
||||
}
|
||||
|
||||
_UpdateOverrideSystem();
|
||||
// update visibility for override message and reset button
|
||||
const auto& obj{ d.try_as<Editor::SettingContainer>() };
|
||||
get_self<SettingContainer>(obj)->_UpdateHelpText();
|
||||
}
|
||||
|
||||
void SettingContainer::_UpdateHelpText()
|
||||
{
|
||||
// Get the correct base to apply automation properties to
|
||||
std::vector<DependencyObject> base;
|
||||
base.reserve(2);
|
||||
@ -215,6 +182,50 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void SettingContainer::OnApplyTemplate()
|
||||
{
|
||||
if (const auto& child{ GetTemplateChild(L"ResetButton") })
|
||||
{
|
||||
if (const auto& button{ child.try_as<Controls::Button>() })
|
||||
{
|
||||
// Apply click handler for the reset button.
|
||||
// When clicked, we dispatch the bound ClearSettingValue event,
|
||||
// resulting in inheriting the setting value from the parent.
|
||||
button.Click([=](auto&&, auto&&) {
|
||||
ClearSettingValue.raise(*this, nullptr);
|
||||
|
||||
// move the focus to the child control
|
||||
if (const auto& content{ Content() })
|
||||
{
|
||||
if (const auto& control{ content.try_as<Controls::Control>() })
|
||||
{
|
||||
control.Focus(FocusState::Programmatic);
|
||||
return;
|
||||
}
|
||||
else if (const auto& panel{ content.try_as<Controls::Panel>() })
|
||||
{
|
||||
for (const auto& panelChild : panel.Children())
|
||||
{
|
||||
if (const auto& panelControl{ panelChild.try_as<Controls::Control>() })
|
||||
{
|
||||
panelControl.Focus(FocusState::Programmatic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we get here, we didn't find something to reasonably focus to.
|
||||
}
|
||||
});
|
||||
|
||||
// apply name (automation property)
|
||||
Automation::AutomationProperties::SetName(child, RS_(L"SettingContainer_OverrideMessageBaseLayer"));
|
||||
}
|
||||
}
|
||||
|
||||
_UpdateOverrideSystem();
|
||||
_UpdateHelpText();
|
||||
}
|
||||
|
||||
void SettingContainer::SetExpanded(bool expanded)
|
||||
{
|
||||
if (const auto& child{ GetTemplateChild(L"Expander") })
|
||||
|
||||
@ -47,9 +47,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
static void _InitializeProperties();
|
||||
static void _OnCurrentValueChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
|
||||
static void _OnHasSettingValueChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
|
||||
static void _OnHelpTextChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
|
||||
static hstring _GenerateOverrideMessage(const IInspectable& settingOrigin);
|
||||
hstring _GenerateAccessibleName();
|
||||
void _UpdateOverrideSystem();
|
||||
void _UpdateHelpText();
|
||||
void _UpdateCurrentValueAutoProp();
|
||||
};
|
||||
}
|
||||
|
||||
@ -176,6 +176,7 @@
|
||||
<Setter Property="LineHeight" Value="16" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource SubgroupHeaderBrush}" />
|
||||
<Setter Property="TextWrapping" Value="WrapWholeWords" />
|
||||
<Setter Property="FontFamily" Value="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets" />
|
||||
</Style>
|
||||
|
||||
<DataTemplate x:Key="ExpanderSettingContainerStringPreviewTemplate">
|
||||
|
||||
@ -84,7 +84,6 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_SETTING(Microsoft.Terminal.Control.TextMeasurement, TextMeasurement);
|
||||
INHERITABLE_SETTING(Boolean, UseBackgroundImageForWindow);
|
||||
INHERITABLE_SETTING(Boolean, DebugFeaturesEnabled);
|
||||
INHERITABLE_SETTING(Boolean, StartOnUserLogin);
|
||||
INHERITABLE_SETTING(Boolean, AlwaysOnTop);
|
||||
INHERITABLE_SETTING(Boolean, AutoHideWindow);
|
||||
INHERITABLE_SETTING(TabSwitcherMode, TabSwitcherMode);
|
||||
|
||||
@ -51,7 +51,6 @@ Author(s):
|
||||
X(Model::LaunchMode, LaunchMode, "launchMode", LaunchMode::DefaultMode) \
|
||||
X(bool, SnapToGridOnResize, "snapToGridOnResize", true) \
|
||||
X(bool, DebugFeaturesEnabled, "debugFeatures", debugFeaturesDefault) \
|
||||
X(bool, StartOnUserLogin, "startOnUserLogin", false) \
|
||||
X(bool, AlwaysOnTop, "alwaysOnTop", false) \
|
||||
X(bool, AutoHideWindow, "autoHideWindow", false) \
|
||||
X(Model::TabSwitcherMode, TabSwitcherMode, "tabSwitcherMode", Model::TabSwitcherMode::InOrder) \
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
|
||||
// Miscellaneous
|
||||
"confirmCloseAllTabs": true,
|
||||
"startOnUserLogin": false,
|
||||
"theme": "dark",
|
||||
"snapToGridOnResize": true,
|
||||
"disableAnimations": false,
|
||||
@ -81,6 +80,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",
|
||||
|
||||
@ -117,7 +117,6 @@ namespace SettingsModelUnitTests
|
||||
"tabWidthMode": "equal",
|
||||
"tabSwitcherMode": "mru",
|
||||
|
||||
"startOnUserLogin": false,
|
||||
"theme": "system",
|
||||
"snapToGridOnResize": true,
|
||||
"disableAnimations": false,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -56,12 +56,12 @@ public:
|
||||
const bool IsUnicode,
|
||||
const bool IsPeek,
|
||||
const bool IsWaitAllowed,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
CONSOLE_API_MSG* pWaitReplyMessage) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT ReadConsoleImpl(IConsoleInputObject& context,
|
||||
std::span<char> buffer,
|
||||
size_t& written,
|
||||
std::unique_ptr<IWaitRoutine>& waiter,
|
||||
CONSOLE_API_MSG* pWaitReplyMessage,
|
||||
const std::wstring_view initialData,
|
||||
const std::wstring_view exeName,
|
||||
INPUT_READ_HANDLE_DATA& readHandleState,
|
||||
@ -73,12 +73,12 @@ public:
|
||||
[[nodiscard]] HRESULT WriteConsoleAImpl(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
CONSOLE_API_MSG* pWaitReplyMessage) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT WriteConsoleWImpl(IConsoleOutputObject& context,
|
||||
const std::wstring_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
|
||||
CONSOLE_API_MSG* pWaitReplyMessage) noexcept override;
|
||||
|
||||
#pragma region ThreadCreationInfo
|
||||
[[nodiscard]] HRESULT GetConsoleLangIdImpl(LANGID& langId) noexcept override;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -110,15 +110,25 @@ static FillConsoleResult FillConsoleImpl(SCREEN_INFORMATION& screenInfo, FillCon
|
||||
switch (mode)
|
||||
{
|
||||
case FillConsoleMode::WriteAttribute:
|
||||
{
|
||||
for (; columns < columnsAvailable && inputPos < lengthToWrite; ++columns, ++inputPos)
|
||||
{
|
||||
infoBuffer[columns].Attributes = input[inputPos];
|
||||
// Overwrite all attributes except for the lead/trail byte markers.
|
||||
// Those are used by WriteConsoleOutputWImplHelper to correctly serialize the input.
|
||||
constexpr auto LT = COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE;
|
||||
auto& attributes = infoBuffer[columns].Attributes;
|
||||
attributes = (input[inputPos] & ~LT) | (attributes & LT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FillConsoleMode::FillAttribute:
|
||||
for (const auto attr = input[0]; columns < columnsAvailable && inputPos < lengthToWrite; ++columns, ++inputPos)
|
||||
{
|
||||
infoBuffer[columns].Attributes = attr;
|
||||
// Overwrite all attributes except for the lead/trail byte markers.
|
||||
// Those are used by WriteConsoleOutputWImplHelper to correctly serialize the input.
|
||||
constexpr auto LT = COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE;
|
||||
auto& attributes = infoBuffer[columns].Attributes;
|
||||
attributes = (attr & ~LT) | (attributes & LT);
|
||||
}
|
||||
break;
|
||||
case FillConsoleMode::WriteCharacter:
|
||||
|
||||
@ -269,17 +269,26 @@ void WriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view& t
|
||||
case UNICODE_LINEFEED:
|
||||
{
|
||||
auto pos = cursor.GetPosition();
|
||||
if (WI_IsFlagClear(screenInfo.OutputMode, DISABLE_NEWLINE_AUTO_RETURN) && pos.x != 0)
|
||||
|
||||
// If DISABLE_NEWLINE_AUTO_RETURN is not set, any LF behaves like a CRLF.
|
||||
if (WI_IsFlagClear(screenInfo.OutputMode, DISABLE_NEWLINE_AUTO_RETURN))
|
||||
{
|
||||
pos.x = 0;
|
||||
// This causes the current \n to be replaced with a \r\n in the ConPTY VT output.
|
||||
wch = 0;
|
||||
lastCharWrapped = true;
|
||||
|
||||
// Setting wch=0 and lastCharWrapped=true will cause the code at the end
|
||||
// of the loop to emit a CRLF. However, we only do this if the preceding
|
||||
// character isn't already a CR. We don't want to emit CR CR LF after all.
|
||||
if (it == beg || it[-1] != '\r')
|
||||
{
|
||||
wch = 0;
|
||||
lastCharWrapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
textBuffer.GetMutableRowByOffset(pos.y).SetWrapForced(false);
|
||||
pos.y = pos.y + 1;
|
||||
AdjustCursorPosition(screenInfo, pos, psScrollY);
|
||||
|
||||
break;
|
||||
}
|
||||
case UNICODE_CARRIAGERETURN:
|
||||
@ -406,30 +415,9 @@ void WriteClearScreen(SCREEN_INFORMATION& screenInfo)
|
||||
// - pwchBuffer - wide character text to be inserted into buffer
|
||||
// - pcbBuffer - byte count of pwchBuffer on the way in, number of bytes consumed on the way out.
|
||||
// - screenInfo - Screen Information class to write the text into at the current cursor position
|
||||
// - ppWaiter - If writing to the console is blocked for whatever reason, this will be filled with a pointer to context
|
||||
// that can be used by the server to resume the call at a later time.
|
||||
// Return Value:
|
||||
// - STATUS_SUCCESS if OK.
|
||||
// - CONSOLE_STATUS_WAIT if we couldn't finish now and need to be called back later (see ppWaiter).
|
||||
// - Or a suitable NTSTATUS format error code for memory/string/math failures.
|
||||
[[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(*pcbBuffer) PCWCHAR pwchBuffer,
|
||||
_Inout_ size_t* const pcbBuffer,
|
||||
SCREEN_INFORMATION& screenInfo,
|
||||
std::unique_ptr<WriteData>& waiter)
|
||||
[[nodiscard]] HRESULT DoWriteConsole(SCREEN_INFORMATION& screenInfo, std::wstring_view str)
|
||||
try
|
||||
{
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
if (WI_IsAnyFlagSet(gci.Flags, (CONSOLE_SUSPENDED | CONSOLE_SELECTING | CONSOLE_SCROLLBAR_TRACKING)))
|
||||
{
|
||||
waiter = std::make_unique<WriteData>(screenInfo,
|
||||
pwchBuffer,
|
||||
*pcbBuffer,
|
||||
gci.OutputCP);
|
||||
return CONSOLE_STATUS_WAIT;
|
||||
}
|
||||
|
||||
const std::wstring_view str{ pwchBuffer, *pcbBuffer / sizeof(WCHAR) };
|
||||
|
||||
if (WI_IsAnyFlagClear(screenInfo.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT))
|
||||
{
|
||||
WriteCharsLegacy(screenInfo, str, nullptr);
|
||||
@ -438,55 +426,9 @@ try
|
||||
{
|
||||
WriteCharsVT(screenInfo, str);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
NT_CATCH_RETURN()
|
||||
|
||||
// Routine Description:
|
||||
// - This method performs the actual work of attempting to write to the console, converting data types as necessary
|
||||
// to adapt from the server types to the legacy internal host types.
|
||||
// - It operates on Unicode data only. It's assumed the text is translated by this point.
|
||||
// Arguments:
|
||||
// - OutContext - the console output object to write the new text into
|
||||
// - pwsTextBuffer - wide character text buffer provided by client application to insert
|
||||
// - cchTextBufferLength - text buffer counted in characters
|
||||
// - pcchTextBufferRead - character count of the number of characters we were able to insert before returning
|
||||
// - ppWaiter - If we are blocked from writing now and need to wait, this is filled with contextual data for the server to restore the call later
|
||||
// Return Value:
|
||||
// - S_OK if successful.
|
||||
// - S_OK if we need to wait (check if ppWaiter is not nullptr).
|
||||
// - Or a suitable HRESULT code for math/string/memory failures.
|
||||
[[nodiscard]] HRESULT WriteConsoleWImplHelper(IConsoleOutputObject& context,
|
||||
const std::wstring_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<WriteData>& waiter) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
// Set out variables in case we exit early.
|
||||
read = 0;
|
||||
waiter.reset();
|
||||
|
||||
// Convert characters to bytes to give to DoWriteConsole.
|
||||
size_t cbTextBufferLength;
|
||||
RETURN_IF_FAILED(SizeTMult(buffer.size(), sizeof(wchar_t), &cbTextBufferLength));
|
||||
|
||||
auto Status = DoWriteConsole(const_cast<wchar_t*>(buffer.data()), &cbTextBufferLength, context, waiter);
|
||||
|
||||
// Convert back from bytes to characters for the resulting string length written.
|
||||
read = cbTextBufferLength / sizeof(wchar_t);
|
||||
|
||||
if (Status == CONSOLE_STATUS_WAIT)
|
||||
{
|
||||
FAIL_FAST_IF_NULL(waiter.get());
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
RETURN_NTSTATUS(Status);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
// Routine Description:
|
||||
// - Writes non-Unicode formatted data into the given console output object.
|
||||
@ -505,13 +447,12 @@ NT_CATCH_RETURN()
|
||||
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
CONSOLE_API_MSG* pWaitReplyMessage) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
// Ensure output variables are initialized.
|
||||
read = 0;
|
||||
waiter.reset();
|
||||
|
||||
if (buffer.empty())
|
||||
{
|
||||
@ -611,67 +552,63 @@ NT_CATCH_RETURN()
|
||||
wstr.resize((dbcsLength + mbPtrLength) / sizeof(wchar_t));
|
||||
}
|
||||
|
||||
// Hold the specific version of the waiter locally so we can tinker with it if we have to store additional context.
|
||||
std::unique_ptr<WriteData> writeDataWaiter{};
|
||||
|
||||
// Make the W version of the call
|
||||
size_t wcBufferWritten{};
|
||||
const auto hr{ WriteConsoleWImplHelper(screenInfo, wstr, wcBufferWritten, writeDataWaiter) };
|
||||
|
||||
// If there is no waiter, process the byte count now.
|
||||
if (nullptr == writeDataWaiter.get())
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
if (WI_IsAnyFlagSet(gci.Flags, (CONSOLE_SUSPENDED | CONSOLE_SELECTING | CONSOLE_SCROLLBAR_TRACKING)))
|
||||
{
|
||||
// Calculate how many bytes of the original A buffer were consumed in the W version of the call to satisfy mbBufferRead.
|
||||
// For UTF-8 conversions, we've already returned this information above.
|
||||
if (CP_UTF8 != codepage)
|
||||
{
|
||||
size_t mbBufferRead{};
|
||||
const auto waiter = new WriteData(screenInfo, std::move(wstr), gci.OutputCP);
|
||||
|
||||
// Start by counting the number of A bytes we used in printing our W string to the screen.
|
||||
try
|
||||
{
|
||||
mbBufferRead = GetALengthFromW(codepage, { wstr.data(), wcBufferWritten });
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// If we captured a byte off the string this time around up above, it means we didn't feed
|
||||
// it into the WriteConsoleW above, and therefore its consumption isn't accounted for
|
||||
// in the count we just made. Add +1 to compensate.
|
||||
if (leadByteCaptured)
|
||||
{
|
||||
mbBufferRead++;
|
||||
}
|
||||
|
||||
// If we consumed an internally-stored lead byte this time around up above, it means that we
|
||||
// fed a byte into WriteConsoleW that wasn't a part of this particular call's request.
|
||||
// We need to -1 to compensate and tell the caller the right number of bytes consumed this request.
|
||||
if (leadByteConsumed)
|
||||
{
|
||||
mbBufferRead--;
|
||||
}
|
||||
|
||||
read = mbBufferRead;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there is a waiter, then we need to stow some additional information in the wait structure so
|
||||
// we can synthesize the correct byte count later when the wait routine is triggered.
|
||||
if (CP_UTF8 != codepage)
|
||||
{
|
||||
// For non-UTF8 codepages, save the lead byte captured/consumed data so we can +1 or -1 the final decoded count
|
||||
// in the WaitData::Notify method later.
|
||||
writeDataWaiter->SetLeadByteAdjustmentStatus(leadByteCaptured, leadByteConsumed);
|
||||
waiter->SetLeadByteAdjustmentStatus(leadByteCaptured, leadByteConsumed);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For UTF8 codepages, just remember the consumption count from the UTF-8 parser.
|
||||
writeDataWaiter->SetUtf8ConsumedCharacters(read);
|
||||
waiter->SetUtf8ConsumedCharacters(read);
|
||||
}
|
||||
|
||||
std::ignore = ConsoleWaitQueue::s_CreateWait(pWaitReplyMessage, waiter);
|
||||
return CONSOLE_STATUS_WAIT;
|
||||
}
|
||||
|
||||
// Give back the waiter now that we're done with tinkering with it.
|
||||
waiter.reset(writeDataWaiter.release());
|
||||
// Make the W version of the call
|
||||
const auto hr = DoWriteConsole(screenInfo, wstr);
|
||||
|
||||
// Calculate how many bytes of the original A buffer were consumed in the W version of the call to satisfy mbBufferRead.
|
||||
// For UTF-8 conversions, we've already returned this information above.
|
||||
if (CP_UTF8 != codepage)
|
||||
{
|
||||
size_t mbBufferRead{};
|
||||
|
||||
// Start by counting the number of A bytes we used in printing our W string to the screen.
|
||||
try
|
||||
{
|
||||
mbBufferRead = GetALengthFromW(codepage, wstr);
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
// If we captured a byte off the string this time around up above, it means we didn't feed
|
||||
// it into the WriteConsoleW above, and therefore its consumption isn't accounted for
|
||||
// in the count we just made. Add +1 to compensate.
|
||||
if (leadByteCaptured)
|
||||
{
|
||||
mbBufferRead++;
|
||||
}
|
||||
|
||||
// If we consumed an internally-stored lead byte this time around up above, it means that we
|
||||
// fed a byte into WriteConsoleW that wasn't a part of this particular call's request.
|
||||
// We need to -1 to compensate and tell the caller the right number of bytes consumed this request.
|
||||
if (leadByteConsumed)
|
||||
{
|
||||
mbBufferRead--;
|
||||
}
|
||||
|
||||
read = mbBufferRead;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
@ -694,20 +631,24 @@ NT_CATCH_RETURN()
|
||||
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleWImpl(IConsoleOutputObject& context,
|
||||
const std::wstring_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
CONSOLE_API_MSG* pWaitReplyMessage) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
LockConsole();
|
||||
auto unlock = wil::scope_exit([&] { UnlockConsole(); });
|
||||
|
||||
std::unique_ptr<WriteData> writeDataWaiter;
|
||||
RETURN_IF_FAILED(WriteConsoleWImplHelper(context.GetActiveBuffer(), buffer, read, writeDataWaiter));
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
if (WI_IsAnyFlagSet(gci.Flags, (CONSOLE_SUSPENDED | CONSOLE_SELECTING | CONSOLE_SCROLLBAR_TRACKING)))
|
||||
{
|
||||
std::ignore = ConsoleWaitQueue::s_CreateWait(pWaitReplyMessage, new WriteData(context, std::wstring{ buffer }, gci.OutputCP));
|
||||
return CONSOLE_STATUS_WAIT;
|
||||
}
|
||||
|
||||
// Transfer specific waiter pointer into the generic interface wrapper.
|
||||
waiter.reset(writeDataWaiter.release());
|
||||
|
||||
return S_OK;
|
||||
read = 0;
|
||||
auto Status = DoWriteConsole(context, buffer);
|
||||
read = buffer.size();
|
||||
return Status;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
@ -25,7 +25,4 @@ void WriteClearScreen(SCREEN_INFORMATION& screenInfo);
|
||||
|
||||
// NOTE: console lock must be held when calling this routine
|
||||
// String has been translated to unicode at this point.
|
||||
[[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(pcbBuffer) const wchar_t* pwchBuffer,
|
||||
_Inout_ size_t* const pcbBuffer,
|
||||
SCREEN_INFORMATION& screenInfo,
|
||||
std::unique_ptr<WriteData>& waiter);
|
||||
[[nodiscard]] HRESULT DoWriteConsole(SCREEN_INFORMATION& screenInfo, std::wstring_view str);
|
||||
|
||||
@ -58,12 +58,10 @@ using Microsoft::Console::Interactivity::ServiceLocator;
|
||||
const bool IsUnicode,
|
||||
const bool IsPeek,
|
||||
const bool IsWaitAllowed,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
CONSOLE_API_MSG* pWaitReplyMessage) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
waiter.reset();
|
||||
|
||||
if (eventReadCount == 0)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
@ -83,9 +81,7 @@ using Microsoft::Console::Interactivity::ServiceLocator;
|
||||
{
|
||||
// If we're told to wait until later, move all of our context
|
||||
// to the read data object and send it back up to the server.
|
||||
waiter = std::make_unique<DirectReadData>(&inputBuffer,
|
||||
&readHandleState,
|
||||
eventReadCount);
|
||||
std::ignore = ConsoleWaitQueue::s_CreateWait(pWaitReplyMessage, new DirectReadData(&inputBuffer, &readHandleState, eventReadCount));
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
@ -87,6 +87,7 @@
|
||||
<Link>
|
||||
<AllowIsolation>true</AllowIsolation>
|
||||
<AdditionalDependencies>winmm.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>icu.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user