Compare commits
38 Commits
dev/cazamo
...
v1.8.1444.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
646904c3c2 | ||
|
|
cb4c4f7b73 | ||
|
|
3c64fcd12b | ||
|
|
7264d5cc43 | ||
|
|
5756236362 | ||
|
|
6e907fd5f2 | ||
|
|
afd6a87de5 | ||
|
|
a3de0d0ece | ||
|
|
a2ab200e88 | ||
|
|
90e78ec074 | ||
|
|
3c30877294 | ||
|
|
e593c46679 | ||
|
|
a736712da9 | ||
|
|
0499604eee | ||
|
|
c8ab75b265 | ||
|
|
b345d39c1d | ||
|
|
c4e02e7274 | ||
|
|
cb7f481c95 | ||
|
|
69397b3797 | ||
|
|
e7ec200f34 | ||
|
|
ba07f65eb9 | ||
|
|
0e810d2c35 | ||
|
|
ed3feef213 | ||
|
|
ca71ac4100 | ||
|
|
fba9493dbb | ||
|
|
ac864d2c65 | ||
|
|
89032b8b1c | ||
|
|
c2cb365c62 | ||
|
|
76a609b3ae | ||
|
|
99e0f95318 | ||
|
|
2c0889223a | ||
|
|
aad3855287 | ||
|
|
4c09a235cc | ||
|
|
8078db5fd5 | ||
|
|
f2afb223f5 | ||
|
|
9882e9f835 | ||
|
|
6072be5436 | ||
|
|
bc368b7c29 |
1
.github/actions/spelling/dictionary/apis.txt
vendored
@@ -28,6 +28,7 @@ GETHIGHCONTRAST
|
||||
Hashtable
|
||||
HIGHCONTRASTON
|
||||
HIGHCONTRASTW
|
||||
hotkeys
|
||||
href
|
||||
IActivation
|
||||
IApp
|
||||
|
||||
1
.github/actions/spelling/expect/expect.txt
vendored
@@ -518,6 +518,7 @@ dealloc
|
||||
Debian
|
||||
debolden
|
||||
debounce
|
||||
debugtype
|
||||
DECALN
|
||||
DECANM
|
||||
DECAUPSS
|
||||
|
||||
@@ -1347,6 +1347,11 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"tabColor": {
|
||||
"$ref": "#/definitions/Color",
|
||||
"description": "Sets the color of the profile's tab. Using the tab color picker will override this color.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"tabTitle": {
|
||||
"description": "If set, will replace the name as the title to pass to the shell on startup. Some shells (like bash) may choose to ignore this initial value, while others (cmd, powershell) may use this value over the lifetime of the application.",
|
||||
"type": ["string", "null"]
|
||||
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 8.2 KiB |
@@ -43,6 +43,7 @@
|
||||
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Server" Name="1A541C01-589A-496E-85A7-A9E02170166D"/>
|
||||
<EventProvider Id="EventProvider-Microsoft.Windows.Console.VirtualTerminal.Parser" Name="c9ba2a84-d3ca-5e19-2bd6-776a0910cb9d"/>
|
||||
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Render.VtEngine" Name="c9ba2a95-d3ca-5e19-2bd6-776a0910cb9d"/>
|
||||
<EventProvider Id="EventProvider-Microsoft.Windows.Console.UIA" Name="e7ebce59-2161-572d-b263-2f16a6afb9e5"/>
|
||||
<!-- Now define some profiles. We'll call them by ID when collecting. Also, the Base is where it is inheriting from and is a .wprpi file built... -->
|
||||
<!-- ... into WPR automatically. Go look in the WPR install directory or in the documentation to find it. -->
|
||||
<Profile Id="ConsolePerfProfile.Verbose.File" Base="GeneralProfile.Light.File" LoggingMode="File" Name="ConsolePerfProfile" DetailLevel="Verbose" Description="Console Performance default profile">
|
||||
@@ -66,6 +67,7 @@
|
||||
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Server"/>
|
||||
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.VirtualTerminal.Parser"/>
|
||||
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Render.VtEngine"/>
|
||||
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.UIA"/>
|
||||
</EventProviders>
|
||||
</EventCollectorId>
|
||||
</Collectors>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<EventProvider Id="EventProvider_TerminalApp" Name="24a1622f-7da7-5c77-3303-d850bd1ab2ed" />
|
||||
<EventProvider Id="EventProvider_TerminalWin32Host" Name="56c06166-2e2e-5f4d-7ff3-74f4b78c87d6" />
|
||||
<EventProvider Id="EventProvider_TerminalRemoting" Name="d6f04aad-629f-539a-77c1-73f5c3e4aa7b" />
|
||||
<EventProvider Id="EventProvider_TerminalDirectX" Name="c93e739e-ae50-5a14-78e7-f171e947535d" />
|
||||
<Profile Id="Terminal.Verbose.File" Name="Terminal" Description="Terminal" LoggingMode="File" DetailLevel="Verbose">
|
||||
<Collectors>
|
||||
<EventCollectorId Value="EventCollector_Terminal">
|
||||
@@ -21,6 +22,7 @@
|
||||
<EventProviderId Value="EventProvider_TerminalApp" />
|
||||
<EventProviderId Value="EventProvider_TerminalWin32Host" />
|
||||
<EventProviderId Value="EventProvider_TerminalRemoting" />
|
||||
<EventProviderId Value="EventProvider_TerminalDirectX" />
|
||||
</EventProviders>
|
||||
</EventCollectorId>
|
||||
</Collectors>
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
<uap:ShowOn Tile="square310x310Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png"/>
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
<uap:ShowOn Tile="square310x310Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png"/>
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
@@ -75,6 +74,7 @@
|
||||
Enabled="false"
|
||||
DisplayName="ms-resource:AppNamePre" />
|
||||
</uap5:Extension>
|
||||
<!-- DISABLED FOR 1.8
|
||||
<uap3:Extension Category="windows.appExtension">
|
||||
<uap3:AppExtension Name="com.microsoft.windows.console.host"
|
||||
Id="OpenConsole-Pre"
|
||||
@@ -97,6 +97,7 @@
|
||||
</uap3:Properties>
|
||||
</uap3:AppExtension>
|
||||
</uap3:Extension>
|
||||
-->
|
||||
<com:Extension Category="windows.comInterface">
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub Id="1833E661-CC81-4DD0-87C6-C2F74BD39EFA" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
<uap:ShowOn Tile="square310x310Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png"/>
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// stay in this jail until we do.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ExceptionInCtor",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +100,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(givenID.value(), "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -108,7 +110,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingPointer(nullptr, "Id", "No ID provided"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -140,7 +143,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(givenID.value(), "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else if (responseId == WindowingBehaviorUseName)
|
||||
{
|
||||
@@ -151,7 +155,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(0, "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,7 +165,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(0, "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(L"", "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +234,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
"WindowManager_ConnectedToMonarch",
|
||||
TraceLoggingUInt64(_monarch.GetPID(), "monarchPID", "The PID of the new Monarch"),
|
||||
TraceLoggingBoolean(_isKing, "isKing", "true if we are the new monarch"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
if (_peasant)
|
||||
{
|
||||
@@ -294,7 +301,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_CreateOurPeasant",
|
||||
TraceLoggingUInt64(_peasant.GetID(), "peasantID", "The ID of our new peasant"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
return _peasant;
|
||||
}
|
||||
@@ -369,7 +377,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
"WindowManager_FailedToOpenMonarch",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingUInt64(gle, "lastError", "The result of GetLastError"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
exitThreadRequested = _performElection();
|
||||
continue;
|
||||
@@ -385,7 +394,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_MonarchDied",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
// Connect to the new monarch, which might be us!
|
||||
// If we become the monarch, then we'll return true and exit this thread.
|
||||
exitThreadRequested = _performElection();
|
||||
@@ -396,7 +406,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_MonarchWaitInterrupted",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
exitThreadRequested = true;
|
||||
break;
|
||||
|
||||
@@ -405,7 +416,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_MonarchWaitTimeout",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
exitThreadRequested = true;
|
||||
break;
|
||||
|
||||
@@ -417,7 +429,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
"WindowManager_WaitFailed",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingUInt64(gle, "lastError", "The result of GetLastError"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
ExitProcess(0);
|
||||
}
|
||||
}
|
||||
@@ -441,7 +454,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ExceptionInWaitThread",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
bool foundNewMonarch = false;
|
||||
while (!foundNewMonarch)
|
||||
{
|
||||
@@ -461,7 +475,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ExceptionInNestedWaitThread",
|
||||
TraceLoggingUInt64(peasantID, "peasantID", "Our peasant ID"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,9 +117,11 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else if (const auto& realArgs = args.ActionArgs().try_as<SendInputArgs>())
|
||||
{
|
||||
const auto termControl = _GetActiveControl();
|
||||
termControl.SendInput(realArgs.Input());
|
||||
args.Handled(true);
|
||||
if (const auto termControl{ _GetActiveControl() })
|
||||
{
|
||||
termControl.SendInput(realArgs.Input());
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,9 +310,11 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<AdjustFontSizeArgs>())
|
||||
{
|
||||
const auto termControl = _GetActiveControl();
|
||||
termControl.AdjustFontSize(realArgs.Delta());
|
||||
args.Handled(true);
|
||||
if (const auto& termControl{ _GetActiveControl() })
|
||||
{
|
||||
termControl.AdjustFontSize(realArgs.Delta());
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,17 +328,21 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_HandleResetFontSize(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
const auto termControl = _GetActiveControl();
|
||||
termControl.ResetFontSize();
|
||||
args.Handled(true);
|
||||
if (const auto& termControl{ _GetActiveControl() })
|
||||
{
|
||||
termControl.ResetFontSize();
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleToggleShaderEffects(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
const auto termControl = _GetActiveControl();
|
||||
termControl.ToggleShaderEffects();
|
||||
args.Handled(true);
|
||||
if (const auto& termControl{ _GetActiveControl() })
|
||||
{
|
||||
termControl.ToggleShaderEffects();
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleToggleFocusMode(const IInspectable& /*sender*/,
|
||||
@@ -719,9 +727,9 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto newName = realArgs.Name();
|
||||
const auto request = winrt::make_self<implementation::RenameWindowRequestedArgs>(newName);
|
||||
_RenameWindowRequestedHandlers(*this, *request);
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
args.Handled(false);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleOpenWindowRenamer(const IInspectable& /*sender*/,
|
||||
|
||||
@@ -493,8 +493,18 @@ NewTerminalArgs AppCommandlineArgs::_getNewTerminalArgs(AppCommandlineArgs::NewT
|
||||
|
||||
if (*subcommand.tabColorOption)
|
||||
{
|
||||
const auto tabColor = Microsoft::Console::Utils::ColorFromHexString(_startingTabColor);
|
||||
args.TabColor(static_cast<winrt::Windows::UI::Color>(tabColor));
|
||||
try
|
||||
{
|
||||
// This is gonna throw whenever the string that's currently being parsed
|
||||
// isn't a valid hex string. Let's just eat anything this throws because
|
||||
// we should only lock in the TabColor arg when the user gives a valid hex
|
||||
// str, and we shouldn't crash when the user gives us anything else.
|
||||
const auto tabColor = Microsoft::Console::Utils::ColorFromHexString(_startingTabColor);
|
||||
args.TabColor(static_cast<winrt::Windows::UI::Color>(tabColor));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (*subcommand.suppressApplicationTitleOption)
|
||||
|
||||
@@ -919,12 +919,32 @@ namespace winrt::TerminalApp::implementation
|
||||
_ApplyTheme(_settings.GlobalSettings().Theme());
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// Returns the current app package or nullptr.
|
||||
// TRANSITIONAL
|
||||
// Exists to work around a compiler bug. This function encapsulates the
|
||||
// exception handling that we used to keep around calls to Package::Current,
|
||||
// so that when it's called inside a coroutine and fails it doesn't explode
|
||||
// terribly.
|
||||
static winrt::Windows::ApplicationModel::Package GetCurrentPackageNoThrow() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
return winrt::Windows::ApplicationModel::Package::Current();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// discard any exception -- literally pretend we're not in a package
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fire_and_forget 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.
|
||||
const auto package{ winrt::Windows::ApplicationModel::Package::Current() };
|
||||
const auto package{ GetCurrentPackageNoThrow() };
|
||||
if (package == nullptr)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -927,6 +927,10 @@ namespace winrt::TerminalApp::implementation
|
||||
ParsedCommandLineText(L"");
|
||||
_searchBox().Text(L"");
|
||||
_searchBox().Select(_searchBox().Text().size(), 0);
|
||||
|
||||
_nestedActionStack.Clear();
|
||||
ParentCommandName(L"");
|
||||
_currentNestedCommands.Clear();
|
||||
// Leaving this block of code outside the above if-statement
|
||||
// guarantees that the correct text is shown for the mode
|
||||
// whenever _switchToMode is called.
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
for (const auto searchChar : _Filter)
|
||||
{
|
||||
const auto lowerCaseSearchChar = std::towlower(searchChar);
|
||||
const WCHAR searchCharAsString[] = { searchChar, L'\0' };
|
||||
while (true)
|
||||
{
|
||||
if (currentOffset == commandName.size())
|
||||
@@ -93,7 +93,10 @@ namespace winrt::TerminalApp::implementation
|
||||
return winrt::make<HighlightedText>(segments);
|
||||
}
|
||||
|
||||
auto isCurrentCharMatched = std::towlower(commandName[currentOffset]) == lowerCaseSearchChar;
|
||||
// GH#9941: search should be locale-aware as well
|
||||
// We use the same comparison method as upon sorting to guarantee consistent behavior
|
||||
const WCHAR currentCharAsString[] = { commandName[currentOffset], L'\0' };
|
||||
auto isCurrentCharMatched = lstrcmpi(searchCharAsString, currentCharAsString) == 0;
|
||||
if (isProcessingMatchedSegment != isCurrentCharMatched)
|
||||
{
|
||||
// We reached the end of the region (matched character came after a series of unmatched or vice versa).
|
||||
|
||||
@@ -62,7 +62,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void SettingsTab::_MakeTabViewItem()
|
||||
{
|
||||
TabViewItem(::winrt::MUX::Controls::TabViewItem{});
|
||||
TabBase::_MakeTabViewItem();
|
||||
|
||||
Title(RS_(L"SettingsTab"));
|
||||
TabViewItem().Header(winrt::box_value(Title()));
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
|
||||
|
||||
private:
|
||||
void _MakeTabViewItem();
|
||||
void _MakeTabViewItem() override;
|
||||
winrt::fire_and_forget _CreateIcon();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,35 +45,27 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
// Close
|
||||
Controls::MenuFlyoutItem closeTabMenuItem;
|
||||
Controls::FontIcon closeSymbol;
|
||||
closeSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
|
||||
closeSymbol.Glyph(L"\xE711");
|
||||
|
||||
closeTabMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
// Build the menu
|
||||
Controls::MenuFlyout contextMenuFlyout;
|
||||
// GH#5750 - When the context menu is dismissed with ESC, toss the focus
|
||||
// back to our control.
|
||||
contextMenuFlyout.Closed([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_CloseRequestedHandlers(nullptr, nullptr);
|
||||
tab->_RequestFocusActiveControlHandlers();
|
||||
}
|
||||
});
|
||||
closeTabMenuItem.Text(RS_(L"TabClose"));
|
||||
closeTabMenuItem.Icon(closeSymbol);
|
||||
|
||||
// Build the menu
|
||||
Controls::MenuFlyout newTabFlyout;
|
||||
newTabFlyout.Items().Append(_CreateCloseSubMenu());
|
||||
newTabFlyout.Items().Append(closeTabMenuItem);
|
||||
TabViewItem().ContextFlyout(newTabFlyout);
|
||||
_AppendCloseMenuItems(contextMenuFlyout);
|
||||
TabViewItem().ContextFlyout(contextMenuFlyout);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates a sub-menu containing menu items to close multiple tabs
|
||||
// - Append the close menu items to the context menu flyout
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// - flyout - the menu flyout to which the close items must be appended
|
||||
// Return Value:
|
||||
// - the created MenuFlyoutSubItem
|
||||
Controls::MenuFlyoutSubItem TabBase::_CreateCloseSubMenu()
|
||||
// - <none>
|
||||
void TabBase::_AppendCloseMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout)
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
@@ -95,12 +87,30 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
_closeOtherTabsMenuItem.Text(RS_(L"TabCloseOther"));
|
||||
|
||||
Controls::MenuFlyoutSubItem closeSubMenu;
|
||||
closeSubMenu.Text(RS_(L"TabCloseSubMenu"));
|
||||
closeSubMenu.Items().Append(_closeTabsAfterMenuItem);
|
||||
closeSubMenu.Items().Append(_closeOtherTabsMenuItem);
|
||||
// Close
|
||||
Controls::MenuFlyoutItem closeTabMenuItem;
|
||||
Controls::FontIcon closeSymbol;
|
||||
closeSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
|
||||
closeSymbol.Glyph(L"\xE711");
|
||||
|
||||
return closeSubMenu;
|
||||
closeTabMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_CloseRequestedHandlers(nullptr, nullptr);
|
||||
}
|
||||
});
|
||||
closeTabMenuItem.Text(RS_(L"TabClose"));
|
||||
closeTabMenuItem.Icon(closeSymbol);
|
||||
|
||||
// GH#8238 append the close menu items to the flyout itself until crash in XAML is fixed
|
||||
//Controls::MenuFlyoutSubItem closeSubMenu;
|
||||
//closeSubMenu.Text(RS_(L"TabCloseSubMenu"));
|
||||
//closeSubMenu.Items().Append(_closeTabsAfterMenuItem);
|
||||
//closeSubMenu.Items().Append(_closeOtherTabsMenuItem);
|
||||
//flyout.Items().Append(closeSubMenu);
|
||||
flyout.Items().Append(_closeTabsAfterMenuItem);
|
||||
flyout.Items().Append(_closeOtherTabsMenuItem);
|
||||
flyout.Items().Append(closeTabMenuItem);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -206,6 +216,7 @@ namespace winrt::TerminalApp::implementation
|
||||
titleRun.Text(_CreateToolTipTitle());
|
||||
|
||||
auto textBlock = WUX::Controls::TextBlock{};
|
||||
textBlock.TextWrapping(WUX::TextWrapping::Wrap);
|
||||
textBlock.TextAlignment(WUX::TextAlignment::Center);
|
||||
textBlock.Inlines().Append(titleRun);
|
||||
|
||||
@@ -222,4 +233,24 @@ namespace winrt::TerminalApp::implementation
|
||||
toolTip.Content(textBlock);
|
||||
WUX::Controls::ToolTipService::SetToolTip(TabViewItem(), toolTip);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Initializes a TabViewItem for this Tab instance.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TabBase::_MakeTabViewItem()
|
||||
{
|
||||
TabViewItem(::winrt::MUX::Controls::TabViewItem{});
|
||||
|
||||
// GH#3609 If the tab was tapped, and no one else was around to handle
|
||||
// it, then ask our parent to toss focus into the active control.
|
||||
TabViewItem().Tapped([weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_RequestFocusActiveControlHandlers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
|
||||
void SetKeyMap(const Microsoft::Terminal::Settings::Model::KeyMapping& keymap);
|
||||
|
||||
WINRT_CALLBACK(RequestFocusActiveControl, winrt::delegate<void()>);
|
||||
|
||||
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
|
||||
WINRT_CALLBACK(CloseRequested, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
@@ -52,7 +54,9 @@ namespace winrt::TerminalApp::implementation
|
||||
virtual void _CreateContextMenu();
|
||||
virtual winrt::hstring _CreateToolTipTitle();
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::MenuFlyoutSubItem _CreateCloseSubMenu();
|
||||
virtual void _MakeTabViewItem();
|
||||
|
||||
void _AppendCloseMenuItems(winrt::Windows::UI::Xaml::Controls::MenuFlyout flyout);
|
||||
void _EnableCloseMenuItems();
|
||||
void _CloseTabsAfter();
|
||||
void _CloseOtherTabs();
|
||||
|
||||
@@ -55,6 +55,18 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if we're in the middle of a tab rename. This is used to
|
||||
// mitigate GH#10112.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - true if the renamer is open.
|
||||
bool TabHeaderControl::InRename()
|
||||
{
|
||||
return Windows::UI::Xaml::Visibility::Visible == HeaderRenamerTextBox().Visibility();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Show the tab rename box for the user to rename the tab title
|
||||
// - We automatically use the previous title as the initial text of the box
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void RenameBoxLostFocusHandler(winrt::Windows::Foundation::IInspectable const& sender,
|
||||
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||
|
||||
bool InRename();
|
||||
|
||||
WINRT_CALLBACK(TitleChangeRequested, TerminalApp::TitleChangeRequestedArgs);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace TerminalApp
|
||||
TabHeaderControl();
|
||||
void BeginRename();
|
||||
|
||||
Boolean InRename { get; };
|
||||
|
||||
TerminalTabStatus TabStatus { get; set; };
|
||||
|
||||
event TitleChangeRequestedArgs TitleChangeRequested;
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace winrt::TerminalApp::implementation
|
||||
newTabImpl->UpdateIcon(profile.Icon());
|
||||
}
|
||||
|
||||
tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick });
|
||||
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabClick });
|
||||
|
||||
// When the tab requests close, try to close it (prompt for approval, if required)
|
||||
newTabImpl->CloseRequested([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
|
||||
@@ -210,7 +210,9 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
newTabImpl->TabRenamerDeactivated([weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
|
||||
// The tab might want us to toss focus into the control, especially when
|
||||
// transient UIs (like the context menu, or the renamer) are dismissed.
|
||||
newTabImpl->RequestFocusActiveControl([weakThis{ get_weak() }]() {
|
||||
if (const auto page{ weakThis.get() })
|
||||
{
|
||||
page->_FocusCurrentTab(false);
|
||||
|
||||
@@ -522,6 +522,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_CreateNewTabFlyout()
|
||||
{
|
||||
auto newTabFlyout = WUX::Controls::MenuFlyout{};
|
||||
newTabFlyout.Placement(WUX::Controls::Primitives::FlyoutPlacementMode::BottomEdgeAlignedLeft);
|
||||
|
||||
auto keyBindings = _settings.KeyMap();
|
||||
|
||||
const auto defaultProfileGuid = _settings.GlobalSettings().DefaultProfile();
|
||||
@@ -711,13 +713,10 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Function Description:
|
||||
// Called when the openNewTabDropdown keybinding is used.
|
||||
// Adds the flyout show option to left-align the dropdown with the split button.
|
||||
// Shows the dropdown flyout.
|
||||
void TerminalPage::_OpenNewTabDropdown()
|
||||
{
|
||||
WUX::Controls::Primitives::FlyoutShowOptions options{};
|
||||
options.Placement(WUX::Controls::Primitives::FlyoutPlacementMode::BottomEdgeAlignedLeft);
|
||||
_newTabButton.Flyout().ShowAt(_newTabButton, options);
|
||||
_newTabButton.Flyout().ShowAt(_newTabButton);
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TerminalPage::_RemoveOnCloseRoutine(Microsoft::UI::Xaml::Controls::TabViewItem tabViewItem, winrt::com_ptr<TerminalPage> page)
|
||||
@@ -903,30 +902,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// Handles preview key on the SUI tab, by handling close tab / next tab / previous tab
|
||||
// This is a temporary solution - we need to fix all key-bindings work from SUI as long as they don't harm
|
||||
// the SUI behavior
|
||||
// Arguments:
|
||||
// - e: the KeyRoutedEventArgs containing info about the keystroke.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_SUIPreviewKeyDownHandler(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
||||
{
|
||||
auto key = e.OriginalKey();
|
||||
auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
|
||||
auto const altDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down);
|
||||
auto const shiftDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down);
|
||||
|
||||
winrt::Microsoft::Terminal::Control::KeyChord kc{ ctrlDown, altDown, shiftDown, static_cast<int32_t>(key) };
|
||||
const auto actionAndArgs = _settings.KeyMap().TryLookup(kc);
|
||||
if (actionAndArgs && (actionAndArgs.Action() == ShortcutAction::CloseTab || actionAndArgs.Action() == ShortcutAction::NextTab || actionAndArgs.Action() == ShortcutAction::PrevTab || actionAndArgs.Action() == ShortcutAction::ClosePane))
|
||||
{
|
||||
_actionDispatch->DoAction(actionAndArgs);
|
||||
e.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Configure the AppKeyBindings to use our ShortcutActionDispatch and the updated KeyMapping
|
||||
// as the object to handle dispatching ShortcutAction events.
|
||||
@@ -1291,10 +1266,12 @@ namespace winrt::TerminalApp::implementation
|
||||
// Do nothing if for some reason, there's no terminal tab in focus. We don't want to crash.
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
const auto control = _GetActiveControl();
|
||||
const auto termHeight = control.GetViewHeight();
|
||||
auto scrollDelta = _ComputeScrollDelta(scrollDirection, termHeight);
|
||||
terminalTab->Scroll(scrollDelta);
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
{
|
||||
const auto termHeight = control.GetViewHeight();
|
||||
auto scrollDelta = _ComputeScrollDelta(scrollDirection, termHeight);
|
||||
terminalTab->Scroll(scrollDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1690,8 +1667,11 @@ namespace winrt::TerminalApp::implementation
|
||||
// - true iff we we able to copy text (if a selection was active)
|
||||
bool TerminalPage::_CopyText(const bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats)
|
||||
{
|
||||
const auto control = _GetActiveControl();
|
||||
return control.CopySelectionToClipboard(singleLine, formats);
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
{
|
||||
return control.CopySelectionToClipboard(singleLine, formats);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1708,8 +1688,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// - Paste text from the Windows Clipboard to the focused terminal
|
||||
void TerminalPage::_PasteText()
|
||||
{
|
||||
const auto control = _GetActiveControl();
|
||||
control.PasteTextFromClipboard();
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
{
|
||||
control.PasteTextFromClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
@@ -2043,8 +2025,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void TerminalPage::_Find()
|
||||
{
|
||||
const auto termControl = _GetActiveControl();
|
||||
termControl.CreateSearchBoxControl();
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
{
|
||||
control.CreateSearchBoxControl();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -2313,7 +2297,8 @@ namespace winrt::TerminalApp::implementation
|
||||
sui.SetHostingWindow(reinterpret_cast<uint64_t>(*_hostingHwnd));
|
||||
}
|
||||
|
||||
sui.PreviewKeyDown({ this, &TerminalPage::_SUIPreviewKeyDownHandler });
|
||||
// GH#8767 - let unhandled keys in the SUI try to run commands too.
|
||||
sui.KeyDown({ this, &TerminalPage::_KeyDownHandler });
|
||||
|
||||
sui.OpenJson([weakThis{ get_weak() }](auto&& /*s*/, winrt::Microsoft::Terminal::Settings::Model::SettingsTarget e) {
|
||||
if (auto page{ weakThis.get() })
|
||||
@@ -2601,12 +2586,32 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
return _WindowName;
|
||||
}
|
||||
void TerminalPage::WindowName(const winrt::hstring& value)
|
||||
|
||||
winrt::fire_and_forget TerminalPage::WindowName(const winrt::hstring& value)
|
||||
{
|
||||
if (_WindowName != value)
|
||||
const bool changed = _WindowName != value;
|
||||
if (changed)
|
||||
{
|
||||
_WindowName = value;
|
||||
_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"WindowNameForDisplay" });
|
||||
}
|
||||
auto weakThis{ get_weak() };
|
||||
// On the foreground thread, raise property changed notifications, and
|
||||
// display the success toast.
|
||||
co_await resume_foreground(Dispatcher());
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
if (changed)
|
||||
{
|
||||
page->_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"WindowName" });
|
||||
page->_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"WindowNameForDisplay" });
|
||||
|
||||
// DON'T display the confirmation if this is the name we were
|
||||
// given on startup!
|
||||
if (page->_startupState == StartupState::Initialized)
|
||||
{
|
||||
page->IdentifyWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// WINRT_OBSERVABLE_PROPERTY's, but we want them to raise
|
||||
// WindowNameForDisplay and WindowIdForDisplay instead
|
||||
winrt::hstring WindowName() const noexcept;
|
||||
void WindowName(const winrt::hstring& value);
|
||||
winrt::fire_and_forget WindowName(const winrt::hstring& value);
|
||||
uint64_t WindowId() const noexcept;
|
||||
void WindowId(const uint64_t& value);
|
||||
winrt::hstring WindowIdForDisplay() const noexcept;
|
||||
@@ -197,7 +197,6 @@ namespace winrt::TerminalApp::implementation
|
||||
void _ThirdPartyNoticesOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
|
||||
void _KeyDownHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
void _SUIPreviewKeyDownHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
void _HookupKeyBindings(const Microsoft::Terminal::Settings::Model::KeyMapping& keymap) noexcept;
|
||||
void _RegisterActionCallbacks();
|
||||
|
||||
|
||||
@@ -53,6 +53,15 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
// GH#9162 - when the header is done renaming, ask for focus to be
|
||||
// tossed back to the control, rather into ourselves.
|
||||
_headerControl.RenameEnded([weakThis = get_weak()](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_RequestFocusActiveControlHandlers();
|
||||
}
|
||||
});
|
||||
|
||||
_UpdateHeaderControlMaxWidth();
|
||||
|
||||
// Use our header control as the TabViewItem's header
|
||||
@@ -83,7 +92,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void TerminalTab::_MakeTabViewItem()
|
||||
{
|
||||
TabViewItem(::winrt::MUX::Controls::TabViewItem{});
|
||||
TabBase::_MakeTabViewItem();
|
||||
|
||||
TabViewItem().DoubleTapped([weakThis = get_weak()](auto&& /*s*/, auto&& /*e*/) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
@@ -784,21 +793,6 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
// Close
|
||||
Controls::MenuFlyoutItem closeTabMenuItem;
|
||||
Controls::FontIcon closeSymbol;
|
||||
closeSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
|
||||
closeSymbol.Glyph(L"\xE711");
|
||||
|
||||
closeTabMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_CloseRequestedHandlers(nullptr, nullptr);
|
||||
}
|
||||
});
|
||||
closeTabMenuItem.Text(RS_(L"TabClose"));
|
||||
closeTabMenuItem.Icon(closeSymbol);
|
||||
|
||||
// "Color..."
|
||||
Controls::MenuFlyoutItem chooseColorMenuItem;
|
||||
Controls::FontIcon colorPickSymbol;
|
||||
@@ -864,15 +858,29 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Build the menu
|
||||
Controls::MenuFlyout newTabFlyout;
|
||||
Controls::MenuFlyout contextMenuFlyout;
|
||||
Controls::MenuFlyoutSeparator menuSeparator;
|
||||
newTabFlyout.Items().Append(chooseColorMenuItem);
|
||||
newTabFlyout.Items().Append(renameTabMenuItem);
|
||||
newTabFlyout.Items().Append(duplicateTabMenuItem);
|
||||
newTabFlyout.Items().Append(menuSeparator);
|
||||
newTabFlyout.Items().Append(_CreateCloseSubMenu());
|
||||
newTabFlyout.Items().Append(closeTabMenuItem);
|
||||
TabViewItem().ContextFlyout(newTabFlyout);
|
||||
contextMenuFlyout.Items().Append(chooseColorMenuItem);
|
||||
contextMenuFlyout.Items().Append(renameTabMenuItem);
|
||||
contextMenuFlyout.Items().Append(duplicateTabMenuItem);
|
||||
contextMenuFlyout.Items().Append(menuSeparator);
|
||||
|
||||
// GH#5750 - When the context menu is dismissed with ESC, toss the focus
|
||||
// back to our control.
|
||||
contextMenuFlyout.Closed([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
// GH#10112 - if we're opening the tab renamer, don't
|
||||
// immediately toss focus to the control. We don't want to steal
|
||||
// focus from the tab renamer.
|
||||
if (!tab->_headerControl.InRename())
|
||||
{
|
||||
tab->_RequestFocusActiveControlHandlers();
|
||||
}
|
||||
}
|
||||
});
|
||||
_AppendCloseMenuItems(contextMenuFlyout);
|
||||
TabViewItem().ContextFlyout(contextMenuFlyout);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -90,7 +90,6 @@ namespace winrt::TerminalApp::implementation
|
||||
DECLARE_EVENT(ColorCleared, _colorCleared, winrt::delegate<>);
|
||||
DECLARE_EVENT(TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>);
|
||||
DECLARE_EVENT(DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>);
|
||||
FORWARDED_TYPED_EVENT(TabRenamerDeactivated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, (&_headerControl), RenameEnded);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Pane> _rootPane{ nullptr };
|
||||
@@ -100,8 +99,6 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::TerminalApp::ColorPickupFlyout _tabColorPickup{};
|
||||
std::optional<winrt::Windows::UI::Color> _themeTabColor{};
|
||||
std::optional<winrt::Windows::UI::Color> _runtimeTabColor{};
|
||||
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeOtherTabsMenuItem{};
|
||||
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{};
|
||||
winrt::TerminalApp::TabHeaderControl _headerControl{};
|
||||
winrt::TerminalApp::TerminalTabStatus _tabStatus{};
|
||||
|
||||
@@ -120,7 +117,7 @@ namespace winrt::TerminalApp::implementation
|
||||
std::optional<Windows::UI::Xaml::DispatcherTimer> _bellIndicatorTimer;
|
||||
void _BellIndicatorTimerTick(Windows::Foundation::IInspectable const& sender, Windows::Foundation::IInspectable const& e);
|
||||
|
||||
void _MakeTabViewItem();
|
||||
void _MakeTabViewItem() override;
|
||||
|
||||
winrt::fire_and_forget _UpdateHeaderControlMaxWidth();
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "ConptyConnection.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <userenv.h>
|
||||
|
||||
#include "ConptyConnection.g.cpp"
|
||||
#include "CTerminalHandoff.h"
|
||||
@@ -95,11 +94,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
environment.clear();
|
||||
});
|
||||
|
||||
{
|
||||
const auto newEnvironmentBlock{ Utils::CreateEnvironmentBlock() };
|
||||
// Populate the environment map with the current environment.
|
||||
RETURN_IF_FAILED(Utils::UpdateEnvironmentMapW(environment, newEnvironmentBlock.get()));
|
||||
}
|
||||
// Populate the environment map with the current environment.
|
||||
RETURN_IF_FAILED(Utils::UpdateEnvironmentMapW(environment));
|
||||
|
||||
{
|
||||
// Convert connection Guid to string and ignore the enclosing '{}'.
|
||||
@@ -298,8 +294,20 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
// EXIT POINT
|
||||
const auto hr = wil::ResultFromCaughtException();
|
||||
|
||||
winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") }, gsl::narrow_cast<unsigned long>(hr), _commandline) };
|
||||
winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") },
|
||||
gsl::narrow_cast<unsigned long>(hr),
|
||||
_commandline) };
|
||||
_TerminalOutputHandlers(failureText);
|
||||
|
||||
// If the path was invalid, let's present an informative message to the user
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_DIRECTORY))
|
||||
{
|
||||
winrt::hstring badPathText{ fmt::format(std::wstring_view{ RS_(L"BadPathText") },
|
||||
_startingDirectory) };
|
||||
_TerminalOutputHandlers(L"\r\n");
|
||||
_TerminalOutputHandlers(badPathText);
|
||||
}
|
||||
|
||||
_transitionToState(ConnectionState::Failed);
|
||||
|
||||
// Tear down any state we may have accumulated.
|
||||
|
||||
@@ -212,4 +212,8 @@
|
||||
<comment>The first argument {0...} is the hexadecimal error code. The second argument {1} is the user-specified path to a program.
|
||||
If this string is broken to multiple lines, it will not be displayed properly.</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="BadPathText" xml:space="preserve">
|
||||
<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>
|
||||
@@ -134,8 +134,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TSFInputControl::TryRedrawCanvas()
|
||||
try
|
||||
{
|
||||
if (!_focused)
|
||||
if (!_focused || !Canvas())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -164,6 +165,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_RedrawCanvas();
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
// Method Description:
|
||||
// - Redraw the Canvas and update the current Text Bounds and Control Bounds for
|
||||
|
||||
@@ -39,6 +39,9 @@ constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(100);
|
||||
// The minimum delay between updating the locations of regex patterns
|
||||
constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(500);
|
||||
|
||||
// The minimum delay between emitting warning bells
|
||||
constexpr const auto TerminalWarningBellInterval = std::chrono::milliseconds(1000);
|
||||
|
||||
DEFINE_ENUM_FLAG_OPERATORS(winrt::Microsoft::Terminal::Control::CopyFormat);
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
@@ -91,7 +94,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// GH#8969: pre-seed working directory to prevent potential races
|
||||
_terminal->SetWorkingDirectory(_settings.StartingDirectory());
|
||||
|
||||
auto pfnWarningBell = std::bind(&TermControl::_TerminalWarningBell, this);
|
||||
auto pfnWarningBell = [this]() {
|
||||
_playWarningBell->Run();
|
||||
};
|
||||
_terminal->SetWarningBellCallback(pfnWarningBell);
|
||||
|
||||
auto pfnTitleChanged = std::bind(&TermControl::_TerminalTitleChanged, this, std::placeholders::_1);
|
||||
@@ -147,27 +152,39 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
});
|
||||
|
||||
_tsfTryRedrawCanvas = std::make_shared<ThrottledFunc<>>(
|
||||
_tsfTryRedrawCanvas = std::make_shared<ThrottledFuncTrailing<>>(
|
||||
Dispatcher(),
|
||||
TsfRedrawInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
if (auto control{ weakThis.get() })
|
||||
{
|
||||
control->TSFInputControl().TryRedrawCanvas();
|
||||
}
|
||||
},
|
||||
TsfRedrawInterval,
|
||||
Dispatcher());
|
||||
});
|
||||
|
||||
_updatePatternLocations = std::make_shared<ThrottledFunc<>>(
|
||||
_updatePatternLocations = std::make_shared<ThrottledFuncTrailing<>>(
|
||||
Dispatcher(),
|
||||
UpdatePatternLocationsInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
if (auto control{ weakThis.get() })
|
||||
{
|
||||
control->UpdatePatternLocations();
|
||||
}
|
||||
},
|
||||
UpdatePatternLocationsInterval,
|
||||
Dispatcher());
|
||||
});
|
||||
|
||||
_updateScrollBar = std::make_shared<ThrottledFunc<ScrollBarUpdate>>(
|
||||
_playWarningBell = std::make_shared<ThrottledFuncLeading>(
|
||||
Dispatcher(),
|
||||
TerminalWarningBellInterval,
|
||||
[weakThis = get_weak()]() {
|
||||
if (auto control{ weakThis.get() })
|
||||
{
|
||||
control->_TerminalWarningBell();
|
||||
}
|
||||
});
|
||||
|
||||
_updateScrollBar = std::make_shared<ThrottledFuncTrailing<ScrollBarUpdate>>(
|
||||
Dispatcher(),
|
||||
ScrollBarUpdateInterval,
|
||||
[weakThis = get_weak()](const auto& update) {
|
||||
if (auto control{ weakThis.get() })
|
||||
{
|
||||
@@ -185,9 +202,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
control->_isInternalScrollBarUpdate = false;
|
||||
}
|
||||
},
|
||||
ScrollBarUpdateInterval,
|
||||
Dispatcher());
|
||||
});
|
||||
|
||||
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
|
||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||
@@ -481,11 +496,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// Update the terminal core with its new Core settings
|
||||
_terminal->UpdateAppearance(newAppearance);
|
||||
|
||||
// Update DxEngine settings under the lock
|
||||
_renderEngine->SetSelectionBackground(til::color{ newAppearance.SelectionBackground() });
|
||||
_renderEngine->SetRetroTerminalEffect(newAppearance.RetroTerminalEffect());
|
||||
_renderEngine->SetPixelShaderPath(newAppearance.PixelShaderPath());
|
||||
_renderer->TriggerRedrawAll();
|
||||
if (_renderEngine)
|
||||
{
|
||||
// Update DxEngine settings under the lock
|
||||
_renderEngine->SetSelectionBackground(til::color{ newAppearance.SelectionBackground() });
|
||||
_renderEngine->SetRetroTerminalEffect(newAppearance.RetroTerminalEffect());
|
||||
_renderEngine->SetPixelShaderPath(newAppearance.PixelShaderPath());
|
||||
_renderer->TriggerRedrawAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -637,6 +655,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
TermControl::~TermControl()
|
||||
{
|
||||
Close();
|
||||
|
||||
if (_renderer)
|
||||
{
|
||||
_renderer->TriggerTeardown();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -656,7 +679,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(autoPeer.get());
|
||||
_renderer->AddRenderEngine(_uiaEngine.get());
|
||||
return *autoPeer;
|
||||
_automationPeer = *autoPeer;
|
||||
return _automationPeer;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -2658,6 +2682,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_connection.TerminalOutput(_connectionOutputEventToken);
|
||||
_connectionStateChangedRevoker.revoke();
|
||||
|
||||
// These four throttled functions are triggered by terminal output and interact with the UI.
|
||||
// Since Close() is the point after which we are removed from the UI, but before the destructor
|
||||
// has run, we should disconnect them *right now*. If we don't, they may fire between the
|
||||
// throttle delay (from the final output) and the dtor.
|
||||
_tsfTryRedrawCanvas.reset();
|
||||
_updatePatternLocations.reset();
|
||||
_updateScrollBar.reset();
|
||||
_playWarningBell.reset();
|
||||
|
||||
TSFInputControl().Close(); // Disconnect the TSF input control so it doesn't receive EditContext events.
|
||||
_autoScrollTimer.Stop();
|
||||
|
||||
@@ -2667,30 +2700,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// don't really care to wait for the connection to be completely
|
||||
// closed. We can just do it whenever.
|
||||
_AsyncCloseConnection();
|
||||
|
||||
{
|
||||
// GH#8734:
|
||||
// We lock the terminal here to make sure it isn't still being
|
||||
// used in the connection thread before we destroy the renderer.
|
||||
// However, we must unlock it again prior to triggering the
|
||||
// teardown, to avoid the render thread being deadlocked. The
|
||||
// renderer may be waiting to acquire the terminal lock, while
|
||||
// we're waiting for the renderer to finish.
|
||||
auto lock = _terminal->LockForWriting();
|
||||
}
|
||||
|
||||
if (auto localRenderEngine{ std::exchange(_renderEngine, nullptr) })
|
||||
{
|
||||
if (auto localRenderer{ std::exchange(_renderer, nullptr) })
|
||||
{
|
||||
localRenderer->TriggerTeardown();
|
||||
// renderer is destroyed
|
||||
}
|
||||
// renderEngine is destroyed
|
||||
}
|
||||
|
||||
// we don't destroy _terminal here; it now has the same lifetime as the
|
||||
// control.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,9 +130,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal;
|
||||
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer;
|
||||
// NOTE: All render engines must be ordered before _renderer.
|
||||
//
|
||||
// As _renderer has a dependency on the render engine (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::DxEngine> _renderEngine;
|
||||
// (further, the TermControlAutomationPeer must be destructed after _uiaEngine!)
|
||||
winrt::Windows::UI::Xaml::Automation::Peers::AutomationPeer _automationPeer{ nullptr };
|
||||
std::unique_ptr<::Microsoft::Console::Render::UiaEngine> _uiaEngine;
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer;
|
||||
|
||||
IControlSettings _settings;
|
||||
bool _focused;
|
||||
@@ -141,9 +148,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
FontInfoDesired _desiredFont;
|
||||
FontInfo _actualFont;
|
||||
|
||||
std::shared_ptr<ThrottledFunc<>> _tsfTryRedrawCanvas;
|
||||
|
||||
std::shared_ptr<ThrottledFunc<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
|
||||
std::shared_ptr<ThrottledFuncLeading> _playWarningBell;
|
||||
|
||||
struct ScrollBarUpdate
|
||||
{
|
||||
@@ -152,7 +159,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
double newMinimum;
|
||||
double newViewportSize;
|
||||
};
|
||||
std::shared_ptr<ThrottledFunc<ScrollBarUpdate>> _updateScrollBar;
|
||||
std::shared_ptr<ThrottledFuncTrailing<ScrollBarUpdate>> _updateScrollBar;
|
||||
bool _isInternalScrollBarUpdate;
|
||||
|
||||
unsigned int _rowsToScroll;
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip x:Name="LinkTip"
|
||||
Placement="Mouse">
|
||||
<TextBlock IsTextSelectionEnabled="True">
|
||||
<TextBlock IsTextSelectionEnabled="True"
|
||||
TextWrapping="Wrap">
|
||||
<Run x:Name="HoveredUri" /> <LineBreak />
|
||||
<Run x:Uid="HowToOpenRun"
|
||||
FontStyle="Italic" />
|
||||
|
||||
@@ -46,9 +46,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControlAutomationPeer::SignalSelectionChanged()
|
||||
{
|
||||
UiaTracing::Signal::SelectionChanged();
|
||||
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
|
||||
// The event that is raised when the text selection is modified.
|
||||
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
auto dispatcher{ Dispatcher() };
|
||||
if (!dispatcher)
|
||||
{
|
||||
return;
|
||||
}
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when the text selection is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,9 +69,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControlAutomationPeer::SignalTextChanged()
|
||||
{
|
||||
UiaTracing::Signal::TextChanged();
|
||||
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
|
||||
// The event that is raised when textual content is modified.
|
||||
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged);
|
||||
auto dispatcher{ Dispatcher() };
|
||||
if (!dispatcher)
|
||||
{
|
||||
return;
|
||||
}
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when textual content is modified.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextChanged);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -76,14 +92,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void TermControlAutomationPeer::SignalCursorChanged()
|
||||
{
|
||||
UiaTracing::Signal::CursorChanged();
|
||||
Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [&]() {
|
||||
// The event that is raised when the text was changed in an edit control.
|
||||
// Do NOT fire a TextEditTextChanged. Generally, an app on the other side
|
||||
// will expect more information. Though you can dispatch that event
|
||||
// on its own, it may result in a nullptr exception on the other side
|
||||
// because no additional information was provided. Crashing the screen
|
||||
// reader.
|
||||
RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
auto dispatcher{ Dispatcher() };
|
||||
if (!dispatcher)
|
||||
{
|
||||
return;
|
||||
}
|
||||
dispatcher.RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [weakThis{ get_weak() }]() {
|
||||
if (auto strongThis{ weakThis.get() })
|
||||
{
|
||||
// The event that is raised when the text was changed in an edit control.
|
||||
// Do NOT fire a TextEditTextChanged. Generally, an app on the other side
|
||||
// will expect more information. Though you can dispatch that event
|
||||
// on its own, it may result in a nullptr exception on the other side
|
||||
// because no additional information was provided. Crashing the screen
|
||||
// reader.
|
||||
strongThis->RaiseAutomationEvent(AutomationEvents::TextPatternOnTextSelectionChanged);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,68 @@ Module Name:
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
template<typename... Args>
|
||||
class ThrottledFuncStorage
|
||||
{
|
||||
public:
|
||||
template<typename... MakeArgs>
|
||||
bool Emplace(MakeArgs&&... args)
|
||||
{
|
||||
std::scoped_lock guard{ _lock };
|
||||
|
||||
const bool hadValue = _pendingRunArgs.has_value();
|
||||
_pendingRunArgs.emplace(std::forward<MakeArgs>(args)...);
|
||||
return hadValue;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void ModifyPending(F f)
|
||||
{
|
||||
std::scoped_lock guard{ _lock };
|
||||
|
||||
if (_pendingRunArgs.has_value())
|
||||
{
|
||||
std::apply(f, _pendingRunArgs.value());
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<Args...> Extract()
|
||||
{
|
||||
decltype(_pendingRunArgs) args;
|
||||
std::scoped_lock guard{ _lock };
|
||||
_pendingRunArgs.swap(args);
|
||||
return args.value();
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex _lock;
|
||||
std::optional<std::tuple<Args...>> _pendingRunArgs;
|
||||
};
|
||||
|
||||
template<>
|
||||
class ThrottledFuncStorage<>
|
||||
{
|
||||
public:
|
||||
bool Emplace()
|
||||
{
|
||||
return _isRunPending.test_and_set(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
std::tuple<> Extract()
|
||||
{
|
||||
Reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_isRunPending.clear(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_flag _isRunPending;
|
||||
};
|
||||
|
||||
// Class Description:
|
||||
// - Represents a function that takes arguments and whose invocation is
|
||||
// delayed by a specified duration and rate-limited such that if the code
|
||||
@@ -16,16 +78,16 @@ Module Name:
|
||||
// pending, then the previous call with the previous arguments will be
|
||||
// cancelled and the call will be made with the new arguments instead.
|
||||
// - The function will be run on the the specified dispatcher.
|
||||
template<typename... Args>
|
||||
class ThrottledFunc : public std::enable_shared_from_this<ThrottledFunc<Args...>>
|
||||
template<bool leading, typename... Args>
|
||||
class ThrottledFunc : public std::enable_shared_from_this<ThrottledFunc<leading, Args...>>
|
||||
{
|
||||
public:
|
||||
using Func = std::function<void(Args...)>;
|
||||
|
||||
ThrottledFunc(Func func, winrt::Windows::Foundation::TimeSpan delay, winrt::Windows::UI::Core::CoreDispatcher dispatcher) :
|
||||
_func{ func },
|
||||
_delay{ delay },
|
||||
_dispatcher{ dispatcher }
|
||||
ThrottledFunc(winrt::Windows::UI::Core::CoreDispatcher dispatcher, winrt::Windows::Foundation::TimeSpan delay, Func func) :
|
||||
_dispatcher{ std::move(dispatcher) },
|
||||
_delay{ std::move(delay) },
|
||||
_func{ std::move(func) }
|
||||
{
|
||||
}
|
||||
|
||||
@@ -37,26 +99,16 @@ public:
|
||||
// - This method is always thread-safe. It can be called multiple times on
|
||||
// different threads.
|
||||
// Arguments:
|
||||
// - arg: the argument to pass to the function
|
||||
// - args: the arguments to pass to the function
|
||||
// Return Value:
|
||||
// - <none>
|
||||
template<typename... MakeArgs>
|
||||
void Run(MakeArgs&&... args)
|
||||
{
|
||||
if (!_storage.Emplace(std::forward<MakeArgs>(args)...))
|
||||
{
|
||||
std::lock_guard guard{ _lock };
|
||||
|
||||
bool hadValue = _pendingRunArgs.has_value();
|
||||
_pendingRunArgs.emplace(std::forward<MakeArgs>(args)...);
|
||||
|
||||
if (hadValue)
|
||||
{
|
||||
// already pending
|
||||
return;
|
||||
}
|
||||
_Fire();
|
||||
}
|
||||
|
||||
_Fire(_delay, _dispatcher, this->weak_from_this());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -81,93 +133,54 @@ public:
|
||||
template<typename F>
|
||||
void ModifyPending(F f)
|
||||
{
|
||||
std::lock_guard guard{ _lock };
|
||||
|
||||
if (_pendingRunArgs.has_value())
|
||||
{
|
||||
std::apply(f, _pendingRunArgs.value());
|
||||
}
|
||||
_storage.ModifyPending(f);
|
||||
}
|
||||
|
||||
private:
|
||||
static winrt::fire_and_forget _Fire(winrt::Windows::Foundation::TimeSpan delay, winrt::Windows::UI::Core::CoreDispatcher dispatcher, std::weak_ptr<ThrottledFunc> weakThis)
|
||||
winrt::fire_and_forget _Fire()
|
||||
{
|
||||
co_await winrt::resume_after(delay);
|
||||
co_await winrt::resume_foreground(dispatcher);
|
||||
const auto dispatcher = _dispatcher;
|
||||
auto weakSelf = this->weak_from_this();
|
||||
|
||||
if (auto self{ weakThis.lock() })
|
||||
if constexpr (leading)
|
||||
{
|
||||
std::optional<std::tuple<Args...>> args;
|
||||
co_await winrt::resume_foreground(dispatcher);
|
||||
|
||||
if (auto self{ weakSelf.lock() })
|
||||
{
|
||||
std::lock_guard guard{ self->_lock };
|
||||
self->_pendingRunArgs.swap(args);
|
||||
self->_func();
|
||||
}
|
||||
else
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
std::apply(self->_func, args.value());
|
||||
co_await winrt::resume_after(_delay);
|
||||
|
||||
if (auto self{ weakSelf.lock() })
|
||||
{
|
||||
self->_storage.Reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
co_await winrt::resume_after(_delay);
|
||||
co_await winrt::resume_foreground(dispatcher);
|
||||
|
||||
if (auto self{ weakSelf.lock() })
|
||||
{
|
||||
std::apply(self->_func, self->_storage.Extract());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Func _func;
|
||||
winrt::Windows::Foundation::TimeSpan _delay;
|
||||
winrt::Windows::UI::Core::CoreDispatcher _dispatcher;
|
||||
winrt::Windows::Foundation::TimeSpan _delay;
|
||||
Func _func;
|
||||
|
||||
std::mutex _lock;
|
||||
std::optional<std::tuple<Args...>> _pendingRunArgs;
|
||||
ThrottledFuncStorage<Args...> _storage;
|
||||
};
|
||||
|
||||
// Class Description:
|
||||
// - Represents a function whose invocation is delayed by a specified duration
|
||||
// and rate-limited such that if the code tries to run the function while a
|
||||
// call to the function is already pending, the request will be ignored.
|
||||
// - The function will be run on the the specified dispatcher.
|
||||
template<>
|
||||
class ThrottledFunc<> : public std::enable_shared_from_this<ThrottledFunc<>>
|
||||
{
|
||||
public:
|
||||
using Func = std::function<void()>;
|
||||
|
||||
ThrottledFunc(Func func, winrt::Windows::Foundation::TimeSpan delay, winrt::Windows::UI::Core::CoreDispatcher dispatcher) :
|
||||
_func{ func },
|
||||
_delay{ delay },
|
||||
_dispatcher{ dispatcher }
|
||||
{
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Runs the function later, except if `Run` is called again before
|
||||
// with a new argument, in which case the request will be ignored.
|
||||
// - For more information, read the class' documentation.
|
||||
// - This method is always thread-safe. It can be called multiple times on
|
||||
// different threads.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
template<typename... MakeArgs>
|
||||
void Run(MakeArgs&&... args)
|
||||
{
|
||||
if (!_isRunPending.test_and_set(std::memory_order_relaxed))
|
||||
{
|
||||
_Fire(_delay, _dispatcher, this->weak_from_this());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static winrt::fire_and_forget _Fire(winrt::Windows::Foundation::TimeSpan delay, winrt::Windows::UI::Core::CoreDispatcher dispatcher, std::weak_ptr<ThrottledFunc> weakThis)
|
||||
{
|
||||
co_await winrt::resume_after(delay);
|
||||
co_await winrt::resume_foreground(dispatcher);
|
||||
|
||||
if (auto self{ weakThis.lock() })
|
||||
{
|
||||
self->_isRunPending.clear(std::memory_order_relaxed);
|
||||
self->_func();
|
||||
}
|
||||
}
|
||||
|
||||
Func _func;
|
||||
winrt::Windows::Foundation::TimeSpan _delay;
|
||||
winrt::Windows::UI::Core::CoreDispatcher _dispatcher;
|
||||
|
||||
std::atomic_flag _isRunPending;
|
||||
};
|
||||
template<typename... Args>
|
||||
using ThrottledFuncTrailing = ThrottledFunc<false, Args...>;
|
||||
using ThrottledFuncLeading = ThrottledFunc<true>;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Microsoft::Terminal::Core
|
||||
virtual bool AddHyperlink(std::wstring_view uri, std::wstring_view params) noexcept = 0;
|
||||
virtual bool EndHyperlink() noexcept = 0;
|
||||
|
||||
virtual bool SetTaskbarProgress(const size_t state, const size_t progress) noexcept = 0;
|
||||
virtual bool SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) noexcept = 0;
|
||||
|
||||
virtual bool SetWorkingDirectory(std::wstring_view uri) noexcept = 0;
|
||||
virtual std::wstring_view GetWorkingDirectory() noexcept = 0;
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "../../cascadia/terminalcore/ITerminalApi.hpp"
|
||||
#include "../../cascadia/terminalcore/ITerminalInput.hpp"
|
||||
|
||||
static constexpr size_t TaskbarMinProgress{ 10 };
|
||||
|
||||
// You have to forward decl the ICoreSettings here, instead of including the header.
|
||||
// If you include the header, there will be compilation errors with other
|
||||
// headers that include Terminal.hpp
|
||||
@@ -124,7 +126,7 @@ public:
|
||||
bool AddHyperlink(std::wstring_view uri, std::wstring_view params) noexcept override;
|
||||
bool EndHyperlink() noexcept override;
|
||||
|
||||
bool SetTaskbarProgress(const size_t state, const size_t progress) noexcept override;
|
||||
bool SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) noexcept override;
|
||||
bool SetWorkingDirectory(std::wstring_view uri) noexcept override;
|
||||
std::wstring_view GetWorkingDirectory() noexcept override;
|
||||
|
||||
|
||||
@@ -619,10 +619,43 @@ bool Terminal::EndHyperlink() noexcept
|
||||
// - progress: indicates the progress value
|
||||
// Return Value:
|
||||
// - true
|
||||
bool Terminal::SetTaskbarProgress(const size_t state, const size_t progress) noexcept
|
||||
bool Terminal::SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) noexcept
|
||||
{
|
||||
_taskbarState = state;
|
||||
_taskbarProgress = progress;
|
||||
_taskbarState = static_cast<size_t>(state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case DispatchTypes::TaskbarState::Clear:
|
||||
// Always set progress to 0 in this case
|
||||
_taskbarProgress = 0;
|
||||
break;
|
||||
case DispatchTypes::TaskbarState::Set:
|
||||
// Always set progress to the value given in this case
|
||||
_taskbarProgress = progress;
|
||||
break;
|
||||
case DispatchTypes::TaskbarState::Indeterminate:
|
||||
// Leave the progress value unchanged in this case
|
||||
break;
|
||||
case DispatchTypes::TaskbarState::Error:
|
||||
case DispatchTypes::TaskbarState::Paused:
|
||||
// In these 2 cases, if the given progress value is 0, then
|
||||
// leave the progress value unchanged, unless the current progress
|
||||
// value is 0, in which case set it to a 'minimum' value (10 in our case);
|
||||
// if the given progress value is greater than 0, then set the progress value
|
||||
if (progress == 0)
|
||||
{
|
||||
if (_taskbarProgress == 0)
|
||||
{
|
||||
_taskbarProgress = TaskbarMinProgress;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taskbarProgress = progress;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (_pfnTaskbarProgressChanged)
|
||||
{
|
||||
_pfnTaskbarProgressChanged();
|
||||
|
||||
@@ -442,7 +442,7 @@ bool TerminalDispatch::DoConEmuAction(const std::wstring_view string) noexcept
|
||||
{
|
||||
// A state parameter is defined, parse it out
|
||||
const auto stateSuccess = Utils::StringToUint(til::at(parts, 1), state);
|
||||
if (!stateSuccess)
|
||||
if (!stateSuccess && !til::at(parts, 1).empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -450,7 +450,7 @@ bool TerminalDispatch::DoConEmuAction(const std::wstring_view string) noexcept
|
||||
{
|
||||
// A progress parameter is also defined, parse it out
|
||||
const auto progressSuccess = Utils::StringToUint(til::at(parts, 2), progress);
|
||||
if (!progressSuccess)
|
||||
if (!progressSuccess && !til::at(parts, 2).empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -467,7 +467,7 @@ bool TerminalDispatch::DoConEmuAction(const std::wstring_view string) noexcept
|
||||
// progress is greater than the maximum allowed value, clamp it to the max
|
||||
progress = TaskbarMaxProgress;
|
||||
}
|
||||
return _terminalApi.SetTaskbarProgress(state, progress);
|
||||
return _terminalApi.SetTaskbarProgress(static_cast<DispatchTypes::TaskbarState>(state), progress);
|
||||
}
|
||||
// 9 is SetWorkingDirectory, which informs the terminal about the current working directory.
|
||||
else if (subParam == 9)
|
||||
|
||||
@@ -362,7 +362,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
BackgroundImagePath(L"desktopWallpaper");
|
||||
}
|
||||
else if (HasBackgroundImagePath())
|
||||
else
|
||||
{
|
||||
// Restore the path we had previously cached. This might be the
|
||||
// empty string.
|
||||
@@ -399,7 +399,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
StartingDirectory(L"");
|
||||
}
|
||||
else if (HasStartingDirectory())
|
||||
else
|
||||
{
|
||||
// Restore the path we had previously cached as long as it wasn't empty
|
||||
// If it was empty, set the starting directory to %USERPROFILE%
|
||||
|
||||
@@ -221,13 +221,26 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::ProfileDe
|
||||
// - a reference to the new profile
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::CreateNewProfile()
|
||||
{
|
||||
if (_allProfiles.Size() == std::numeric_limits<uint32_t>::max())
|
||||
{
|
||||
// Shouldn't really happen
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::hstring newName{};
|
||||
for (uint32_t candidateIndex = 0; candidateIndex < _allProfiles.Size() + 1; candidateIndex++)
|
||||
{
|
||||
// There is a theoretical unsigned integer wraparound, which is OK
|
||||
newName = fmt::format(L"Profile {}", _allProfiles.Size() + 1 + candidateIndex);
|
||||
if (std::none_of(begin(_allProfiles), end(_allProfiles), [&](auto&& profile) { return profile.Name() == newName; }))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto newProfile{ _userDefaultProfileSettings->CreateChild() };
|
||||
_allProfiles.Append(*newProfile);
|
||||
|
||||
// Give the new profile a distinct name so a guid is properly generated
|
||||
const winrt::hstring newName{ fmt::format(L"Profile {}", _allProfiles.Size()) };
|
||||
newProfile->Name(newName);
|
||||
|
||||
_allProfiles.Append(*newProfile);
|
||||
return *newProfile;
|
||||
}
|
||||
|
||||
|
||||
@@ -846,6 +846,18 @@ bool CascadiaSettings::_AppendDynamicProfilesToUserSettings()
|
||||
return changedFile;
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Given a json serialization of a profile, this function will determine
|
||||
// whether it is "well-formed". We introduced a bug (GH#9962, fixed in GH#9964)
|
||||
// that would result in one or more nameless, guid-less profiles being emitted
|
||||
// into the user's settings file. Those profiles would show up in the list as
|
||||
// "Default" later.
|
||||
static bool _IsValidProfileObject(const Json::Value& profileJson)
|
||||
{
|
||||
return profileJson.isMember(&*NameKey.cbegin(), (&*NameKey.cbegin()) + NameKey.size()) || // has a name (can generate a guid)
|
||||
profileJson.isMember(&*GuidKey.cbegin(), (&*GuidKey.cbegin()) + GuidKey.size()); // or has a guid
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create a new instance of this class from a serialized JsonObject.
|
||||
// Arguments:
|
||||
@@ -888,7 +900,7 @@ void CascadiaSettings::LayerJson(const Json::Value& json)
|
||||
|
||||
for (auto profileJson : _GetProfilesJsonObject(json))
|
||||
{
|
||||
if (profileJson.isObject())
|
||||
if (profileJson.isObject() && _IsValidProfileObject(profileJson))
|
||||
{
|
||||
_LayerOrCreateProfile(profileJson);
|
||||
}
|
||||
|
||||
@@ -413,21 +413,17 @@ std::wstring Profile::EvaluateStartingDirectory(const std::wstring& directory)
|
||||
std::unique_ptr<wchar_t[]> evaluatedPath = std::make_unique<wchar_t[]>(numCharsInput);
|
||||
THROW_LAST_ERROR_IF(0 == ExpandEnvironmentStrings(directory.c_str(), evaluatedPath.get(), numCharsInput));
|
||||
|
||||
// Validate that the resulting path is legitimate
|
||||
const DWORD dwFileAttributes = GetFileAttributes(evaluatedPath.get());
|
||||
if ((dwFileAttributes != INVALID_FILE_ATTRIBUTES) && (WI_IsFlagSet(dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)))
|
||||
{
|
||||
return std::wstring(evaluatedPath.get(), numCharsInput);
|
||||
}
|
||||
else
|
||||
{
|
||||
// In the event where the user supplied a path that can't be resolved, use a reasonable default (in this case, %userprofile%)
|
||||
const DWORD numCharsDefault = ExpandEnvironmentStrings(DEFAULT_STARTING_DIRECTORY.c_str(), nullptr, 0);
|
||||
std::unique_ptr<wchar_t[]> defaultPath = std::make_unique<wchar_t[]>(numCharsDefault);
|
||||
THROW_LAST_ERROR_IF(0 == ExpandEnvironmentStrings(DEFAULT_STARTING_DIRECTORY.c_str(), defaultPath.get(), numCharsDefault));
|
||||
|
||||
return std::wstring(defaultPath.get(), numCharsDefault);
|
||||
}
|
||||
// Prior to GH#9541, we'd validate that the user's startingDirectory existed
|
||||
// here. If it was invalid, we'd gracefully fall back to %USERPROFILE%.
|
||||
//
|
||||
// However, that could cause hangs when combined with WSL. When the WSL
|
||||
// filesystem is slow to respond, we'll end up waiting indefinitely for
|
||||
// their filesystem driver to respond. This can result in the whole terminal
|
||||
// becoming unresponsive.
|
||||
//
|
||||
// If the path is eventually invalid, we'll display warning in the
|
||||
// ConptyConnection when the process fails to launch.
|
||||
return std::wstring(evaluatedPath.get(), numCharsInput);
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
@@ -496,11 +492,16 @@ Json::Value Profile::ToJson() const
|
||||
// Initialize the json with the appearance settings
|
||||
Json::Value json{ winrt::get_self<implementation::AppearanceConfig>(_DefaultAppearance)->ToJson() };
|
||||
|
||||
// GH #9962:
|
||||
// If the settings.json was missing, when we load the dynamic profiles, they are completely empty.
|
||||
// This caused us to serialize empty profiles "{}" on accident.
|
||||
const bool writeBasicSettings{ !Source().empty() };
|
||||
|
||||
// Profile-specific Settings
|
||||
JsonUtils::SetValueForKey(json, NameKey, _Name);
|
||||
JsonUtils::SetValueForKey(json, GuidKey, _Guid);
|
||||
JsonUtils::SetValueForKey(json, HiddenKey, _Hidden);
|
||||
JsonUtils::SetValueForKey(json, SourceKey, _Source);
|
||||
JsonUtils::SetValueForKey(json, NameKey, writeBasicSettings ? Name() : _Name);
|
||||
JsonUtils::SetValueForKey(json, GuidKey, writeBasicSettings ? Guid() : _Guid);
|
||||
JsonUtils::SetValueForKey(json, HiddenKey, writeBasicSettings ? Hidden() : _Hidden);
|
||||
JsonUtils::SetValueForKey(json, SourceKey, writeBasicSettings ? Source() : _Source);
|
||||
|
||||
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
|
||||
JsonUtils::SetValueForKey(json, HistorySizeKey, _HistorySize);
|
||||
|
||||
@@ -388,6 +388,30 @@ void TerminalCoreUnitTests::TerminalApiTest::SetTaskbarProgress()
|
||||
// Additional params should be ignored, state and progress still set normally
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
|
||||
|
||||
// Edge cases + trailing semicolon testing
|
||||
stateMachine.ProcessString(L"\x1b]9;4;2;\x9c");
|
||||
// String should be processed correctly despite the trailing semicolon,
|
||||
// taskbar progress should remain unchanged from previous value
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(2));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;4;3;75\x9c");
|
||||
// Given progress value should be ignored because this is the indeterminate state,
|
||||
// so the progress value should remain unchanged
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(3));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;4;0;50\x9c");
|
||||
// Taskbar progress should be 0 (the given value should be ignored)
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
|
||||
|
||||
stateMachine.ProcessString(L"\x1b]9;4;2;\x9c");
|
||||
// String should be processed correctly despite the trailing semicolon,
|
||||
// taskbar progress should be set to a 'minimum', non-zero value
|
||||
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(2));
|
||||
VERIFY_IS_GREATER_THAN(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
|
||||
}
|
||||
|
||||
void TerminalCoreUnitTests::TerminalApiTest::SetWorkingDirectory()
|
||||
|
||||
@@ -758,6 +758,91 @@ void IslandWindow::_SetIsBorderless(const bool borderlessEnabled)
|
||||
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when entering fullscreen, with the window's current monitor rect and work area.
|
||||
// - The current window position, dpi, work area, and maximized state are stored, and the
|
||||
// window is positioned to the monitor rect.
|
||||
void IslandWindow::_SetFullscreenPosition(const RECT rcMonitor, const RECT rcWork)
|
||||
{
|
||||
HWND const hWnd = GetHandle();
|
||||
|
||||
::GetWindowRect(hWnd, &_rcWindowBeforeFullscreen);
|
||||
_dpiBeforeFullscreen = GetDpiForWindow(hWnd);
|
||||
_fWasMaximizedBeforeFullscreen = IsZoomed(hWnd);
|
||||
_rcWorkBeforeFullscreen = rcWork;
|
||||
|
||||
SetWindowPos(hWnd,
|
||||
HWND_TOP,
|
||||
rcMonitor.left,
|
||||
rcMonitor.top,
|
||||
rcMonitor.right - rcMonitor.left,
|
||||
rcMonitor.bottom - rcMonitor.top,
|
||||
SWP_FRAMECHANGED);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when exiting fullscreen, with the window's current monitor work area.
|
||||
// - The window is restored to its previous position, migrating that previous position to the
|
||||
// window's current monitor (if the current work area or window DPI have changed).
|
||||
// - A fullscreen window's monitor can be changed by win+shift+left/right hotkeys or monitor
|
||||
// topology changes (for example unplugging a monitor or disconnecting a remote session).
|
||||
void IslandWindow::_RestoreFullscreenPosition(const RECT rcWork)
|
||||
{
|
||||
HWND const hWnd = GetHandle();
|
||||
|
||||
// If the window was previously maximized, re-maximize the window.
|
||||
if (_fWasMaximizedBeforeFullscreen)
|
||||
{
|
||||
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
|
||||
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Start with the stored window position.
|
||||
RECT rcRestore = _rcWindowBeforeFullscreen;
|
||||
|
||||
// If the window DPI has changed, re-size the stored position by the change in DPI. This
|
||||
// ensures the window restores to the same logical size (even if to a monitor with a different
|
||||
// DPI/ scale factor).
|
||||
UINT dpiWindow = GetDpiForWindow(hWnd);
|
||||
rcRestore.right = rcRestore.left + MulDiv(rcRestore.right - rcRestore.left, dpiWindow, _dpiBeforeFullscreen);
|
||||
rcRestore.bottom = rcRestore.top + MulDiv(rcRestore.bottom - rcRestore.top, dpiWindow, _dpiBeforeFullscreen);
|
||||
|
||||
// Offset the stored position by the difference in work area.
|
||||
OffsetRect(&rcRestore,
|
||||
rcWork.left - _rcWorkBeforeFullscreen.left,
|
||||
rcWork.top - _rcWorkBeforeFullscreen.top);
|
||||
|
||||
// Enforce that our position is entirely within the bounds of our work area.
|
||||
// Prefer the top-left be on-screen rather than bottom-right (right before left, bottom before top).
|
||||
if (rcRestore.right > rcWork.right)
|
||||
{
|
||||
OffsetRect(&rcRestore, rcWork.right - rcRestore.right, 0);
|
||||
}
|
||||
if (rcRestore.left < rcWork.left)
|
||||
{
|
||||
OffsetRect(&rcRestore, rcWork.left - rcRestore.left, 0);
|
||||
}
|
||||
if (rcRestore.bottom > rcWork.bottom)
|
||||
{
|
||||
OffsetRect(&rcRestore, 0, rcWork.bottom - rcRestore.bottom);
|
||||
}
|
||||
if (rcRestore.top < rcWork.top)
|
||||
{
|
||||
OffsetRect(&rcRestore, 0, rcWork.top - rcRestore.top);
|
||||
}
|
||||
|
||||
// Show the window at the computed position.
|
||||
SetWindowPos(hWnd,
|
||||
HWND_TOP,
|
||||
rcRestore.left,
|
||||
rcRestore.top,
|
||||
rcRestore.right - rcRestore.left,
|
||||
rcRestore.bottom - rcRestore.top,
|
||||
SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Controls setting us into or out of fullscreen mode. Largely taken from
|
||||
// Window::SetIsFullscreen in conhost.
|
||||
@@ -773,7 +858,7 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
|
||||
// It is possible to enter _SetIsFullscreen even if we're already in full
|
||||
// screen. Use the old is in fullscreen flag to gate checks that rely on the
|
||||
// current state.
|
||||
const auto oldIsInFullscreen = _fullscreen;
|
||||
const bool fChangingFullscreen = (fullscreenEnabled != _fullscreen);
|
||||
_fullscreen = fullscreenEnabled;
|
||||
|
||||
HWND const hWnd = GetHandle();
|
||||
@@ -789,61 +874,27 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
|
||||
WI_UpdateFlag(exWindowStyle, WS_EX_WINDOWEDGE, !_fullscreen);
|
||||
_SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle);
|
||||
|
||||
// When entering/exiting fullscreen mode, we also need to backup/restore the
|
||||
// current window size, and resize the window to match the new state.
|
||||
_BackupWindowSizes(oldIsInFullscreen);
|
||||
_ApplyWindowSize();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Used in entering/exiting fullscreen mode. Saves the current window size,
|
||||
// and the full size of the monitor, for use in _ApplyWindowSize.
|
||||
// - Taken from conhost's Window::_BackupWindowSizes
|
||||
// Arguments:
|
||||
// - fCurrentIsInFullscreen: true if we're currently in fullscreen mode.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::_BackupWindowSizes(const bool fCurrentIsInFullscreen)
|
||||
{
|
||||
if (_fullscreen)
|
||||
// Only change the window position if changing fullscreen state.
|
||||
if (fChangingFullscreen)
|
||||
{
|
||||
// Note: the current window size depends on the current state of the
|
||||
// window. So don't back it up if we're already in full screen.
|
||||
if (!fCurrentIsInFullscreen)
|
||||
{
|
||||
_nonFullscreenWindowSize = GetWindowRect();
|
||||
}
|
||||
// Get the monitor info for the window's current monitor.
|
||||
MONITORINFO mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &mi);
|
||||
|
||||
// get and back up the current monitor's size
|
||||
HMONITOR const hCurrentMonitor = MonitorFromWindow(GetHandle(), MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO currMonitorInfo;
|
||||
currMonitorInfo.cbSize = sizeof(currMonitorInfo);
|
||||
if (GetMonitorInfo(hCurrentMonitor, &currMonitorInfo))
|
||||
if (_fullscreen)
|
||||
{
|
||||
_fullscreenWindowSize = currMonitorInfo.rcMonitor;
|
||||
// Store the window's current position and size the window to the monitor.
|
||||
_SetFullscreenPosition(mi.rcMonitor, mi.rcWork);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore the stored window position.
|
||||
_RestoreFullscreenPosition(mi.rcWork);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Applies the appropriate window size for transitioning to/from fullscreen mode.
|
||||
// - Taken from conhost's Window::_ApplyWindowSize
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::_ApplyWindowSize()
|
||||
{
|
||||
const auto newSize = _fullscreen ? _fullscreenWindowSize : _nonFullscreenWindowSize;
|
||||
LOG_IF_WIN32_BOOL_FALSE(SetWindowPos(GetHandle(),
|
||||
HWND_TOP,
|
||||
newSize.left,
|
||||
newSize.top,
|
||||
newSize.right - newSize.left,
|
||||
newSize.bottom - newSize.top,
|
||||
SWP_FRAMECHANGED | SWP_NOACTIVATE));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Force activate this window. This method will bring us to the foreground and
|
||||
// activate us. If the window is minimized, it will restore the window. If the
|
||||
|
||||
@@ -68,15 +68,17 @@ protected:
|
||||
[[nodiscard]] LRESULT _OnSizing(const WPARAM wParam, const LPARAM lParam);
|
||||
|
||||
bool _borderless{ false };
|
||||
bool _fullscreen{ false };
|
||||
bool _alwaysOnTop{ false };
|
||||
RECT _fullscreenWindowSize;
|
||||
RECT _nonFullscreenWindowSize;
|
||||
bool _fullscreen{ false };
|
||||
bool _fWasMaximizedBeforeFullscreen{ false };
|
||||
RECT _rcWindowBeforeFullscreen;
|
||||
RECT _rcWorkBeforeFullscreen;
|
||||
UINT _dpiBeforeFullscreen;
|
||||
|
||||
virtual void _SetIsBorderless(const bool borderlessEnabled);
|
||||
virtual void _SetIsFullscreen(const bool fullscreenEnabled);
|
||||
void _BackupWindowSizes(const bool currentIsInFullscreen);
|
||||
void _ApplyWindowSize();
|
||||
void _RestoreFullscreenPosition(const RECT rcWork);
|
||||
void _SetFullscreenPosition(const RECT rcMonitor, const RECT rcWork);
|
||||
|
||||
LONG _getDesiredWindowStyle() const;
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Terminal.ThemeHelpers.0.2.200324001\build\native\Terminal.ThemeHelpers.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Terminal.ThemeHelpers.0.2.200324001\build\native\Terminal.ThemeHelpers.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.Internal.Windows.Terminal.ThemeHelpers.0.3.210521003\build\native\Microsoft.Internal.Windows.Terminal.ThemeHelpers.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Internal.Windows.Terminal.ThemeHelpers.0.3.210521003\build\native\Microsoft.Internal.Windows.Terminal.ThemeHelpers.targets'))" />
|
||||
</Target>
|
||||
|
||||
<!-- Override GetPackagingOutputs to roll up all our dependencies.
|
||||
@@ -170,6 +170,6 @@
|
||||
</Target>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)\build\rules\GenerateSxsManifestsFromWinmds.targets" />
|
||||
<Import Project="..\..\..\packages\Terminal.ThemeHelpers.0.2.200324001\build\native\Terminal.ThemeHelpers.targets" Condition="Exists('..\..\..\packages\Terminal.ThemeHelpers.0.2.200324001\build\native\Terminal.ThemeHelpers.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Internal.Windows.Terminal.ThemeHelpers.0.3.210521003\build\native\Microsoft.Internal.Windows.Terminal.ThemeHelpers.targets" Condition="Exists('..\..\..\packages\Microsoft.Internal.Windows.Terminal.ThemeHelpers.0.3.210521003\build\native\Microsoft.Internal.Windows.Terminal.ThemeHelpers.targets')" />
|
||||
</Project>
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.2" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.5.0-prerelease.201202003" targetFramework="native" />
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
|
||||
<package id="Terminal.ThemeHelpers" version="0.2.200324001" targetFramework="native" />
|
||||
</packages>
|
||||
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.3.210521003" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -76,7 +76,8 @@ namespace Microsoft.Terminal.Wpf
|
||||
/// <param name="theme">The color theme to use in the terminal.</param>
|
||||
/// <param name="fontFamily">The font family to use in the terminal.</param>
|
||||
/// <param name="fontSize">The font size to use in the terminal.</param>
|
||||
public void SetTheme(TerminalTheme theme, string fontFamily, short fontSize)
|
||||
/// <param name="externalBackground">Color for the control background when the terminal window is smaller than the hosting WPF window.</param>
|
||||
public void SetTheme(TerminalTheme theme, string fontFamily, short fontSize, Color externalBackground = default)
|
||||
{
|
||||
PresentationSource source = PresentationSource.FromVisual(this);
|
||||
|
||||
@@ -92,7 +93,12 @@ namespace Microsoft.Terminal.Wpf
|
||||
byte g = Convert.ToByte((theme.DefaultBackground >> 8) & 0xff);
|
||||
byte r = Convert.ToByte(theme.DefaultBackground & 0xff);
|
||||
|
||||
this.terminalGrid.Background = new SolidColorBrush(Color.FromRgb(r, g, b));
|
||||
// Set the background color for the control only if one is provided.
|
||||
// This is only shown when the terminal renderer is smaller than the enclosing WPF window.
|
||||
if (externalBackground != default)
|
||||
{
|
||||
this.Background = new SolidColorBrush(externalBackground);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
namespace Microsoft.Terminal.Wpf
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalOptions>/debugtype:cv,fixup %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
|
||||
@@ -143,7 +143,11 @@ static bool ShouldUseLegacyConhost(const ConsoleArguments& args)
|
||||
// because there's already a count of how many total processes were launched.
|
||||
// Total - legacy = new console.
|
||||
// We expect legacy launches to be infrequent enough to not cause an issue.
|
||||
TraceLoggingWrite(g_ConhostLauncherProvider, "IsLegacyLoaded", TraceLoggingBool(true, "ConsoleLegacy"), TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY));
|
||||
TraceLoggingWrite(g_ConhostLauncherProvider,
|
||||
"IsLegacyLoaded",
|
||||
TraceLoggingBool(true, "ConsoleLegacy"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
const PCWSTR pszConhostDllName = L"ConhostV1.dll";
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
|
||||
// NOTE: See `til.h` for which keyword flags are reserved
|
||||
// to ensure newly added ones do NOT overlap.
|
||||
enum TraceKeywords
|
||||
{
|
||||
//Font = 0x001, // _DBGFONTS
|
||||
@@ -63,6 +65,7 @@ Tracing Tracing::s_TraceApiCall(const NTSTATUS& result, PCSTR traceName)
|
||||
TraceLoggingString(traceName, "ApiName"),
|
||||
TraceLoggingOpcode(WINEVENT_OPCODE_START),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
|
||||
return Tracing([traceName, &result] {
|
||||
@@ -73,6 +76,7 @@ Tracing Tracing::s_TraceApiCall(const NTSTATUS& result, PCSTR traceName)
|
||||
TraceLoggingHResult(result, "Result"),
|
||||
TraceLoggingOpcode(WINEVENT_OPCODE_STOP),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
});
|
||||
// clang-format on
|
||||
@@ -89,6 +93,7 @@ void Tracing::s_TraceApi(const NTSTATUS status, const CONSOLE_GETLARGESTWINDOWSI
|
||||
TraceLoggingInt32(a->Size.X, "MaxWindowWidthInChars"),
|
||||
TraceLoggingInt32(a->Size.Y, "MaxWindowHeightInChars"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
|
||||
@@ -110,6 +115,7 @@ void Tracing::s_TraceApi(const NTSTATUS status, const CONSOLE_SCREENBUFFERINFO_M
|
||||
TraceLoggingInt32(a->MaximumWindowSize.X, "MaxWindowWidthInChars"),
|
||||
TraceLoggingInt32(a->MaximumWindowSize.Y, "MaxWindowHeightInChars"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
else
|
||||
@@ -125,6 +131,7 @@ void Tracing::s_TraceApi(const NTSTATUS status, const CONSOLE_SCREENBUFFERINFO_M
|
||||
TraceLoggingInt32(a->MaximumWindowSize.X, "MaxWindowWidthInChars"),
|
||||
TraceLoggingInt32(a->MaximumWindowSize.Y, "MaxWindowHeightInChars"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
}
|
||||
@@ -138,6 +145,7 @@ void Tracing::s_TraceApi(const NTSTATUS status, const CONSOLE_SETSCREENBUFFERSIZ
|
||||
TraceLoggingInt32(a->Size.X, "BufferWidthInChars"),
|
||||
TraceLoggingInt32(a->Size.Y, "BufferHeightInChars"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
|
||||
@@ -153,6 +161,7 @@ void Tracing::s_TraceApi(const NTSTATUS status, const CONSOLE_SETWINDOWINFO_MSG*
|
||||
TraceLoggingInt32(a->Window.Top, "WindowRectTop"),
|
||||
TraceLoggingInt32(a->Window.Bottom, "WindowRectBottom"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
|
||||
@@ -169,6 +178,7 @@ void Tracing::s_TraceApi(_In_ const void* const buffer, const CONSOLE_WRITECONSO
|
||||
TraceLoggingUInt32(a->NumBytes, "NumBytes"),
|
||||
TraceLoggingCountedWideString(buf, static_cast<UINT16>(a->NumBytes / sizeof(wchar_t)), "input buffer"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
else
|
||||
@@ -181,6 +191,7 @@ void Tracing::s_TraceApi(_In_ const void* const buffer, const CONSOLE_WRITECONSO
|
||||
TraceLoggingUInt32(a->NumBytes, "NumBytes"),
|
||||
TraceLoggingCountedString(buf, static_cast<UINT16>(a->NumBytes / sizeof(char)), "input buffer"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
// clang-format on
|
||||
@@ -206,6 +217,7 @@ void Tracing::s_TraceApi(const CONSOLE_SCREENBUFFERINFO_MSG* const a)
|
||||
TraceLoggingBoolean(a->FullscreenSupported, "FullscreenSupported"),
|
||||
TraceLoggingHexUInt32FixedArray((UINT32 const*)a->ColorTable, _countof(a->ColorTable), "ColorTable"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
static_assert(sizeof(UINT32) == sizeof(*a->ColorTable), "a->ColorTable");
|
||||
}
|
||||
@@ -218,6 +230,7 @@ void Tracing::s_TraceApi(const CONSOLE_MODE_MSG* const a, const std::wstring_vie
|
||||
TraceLoggingHexUInt32(a->Mode, "Mode"),
|
||||
TraceLoggingCountedWideString(handleType.data(), gsl::narrow_cast<ULONG>(handleType.size()), "Handle type"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
|
||||
@@ -228,6 +241,7 @@ void Tracing::s_TraceApi(const CONSOLE_SETTEXTATTRIBUTE_MSG* const a)
|
||||
"API_SetConsoleTextAttribute",
|
||||
TraceLoggingHexUInt16(a->Attributes, "Attributes"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
|
||||
@@ -241,6 +255,7 @@ void Tracing::s_TraceApi(const CONSOLE_WRITECONSOLEOUTPUTSTRING_MSG* const a)
|
||||
TraceLoggingHexUInt32(a->StringType, "StringType"),
|
||||
TraceLoggingUInt32(a->NumRecords, "NumRecords"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::API));
|
||||
}
|
||||
|
||||
@@ -254,6 +269,7 @@ void Tracing::s_TraceWindowViewport(const Viewport& viewport)
|
||||
TraceLoggingInt32(viewport.Top(), "OriginTop"),
|
||||
TraceLoggingInt32(viewport.Left(), "OriginLeft"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::General));
|
||||
}
|
||||
|
||||
@@ -270,6 +286,7 @@ void Tracing::s_TraceChars(_In_z_ const char* pszMessage, ...)
|
||||
"CharsTrace",
|
||||
TraceLoggingString(szBuffer),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Chars));
|
||||
|
||||
if (s_ulDebugFlag & TraceKeywords::Chars)
|
||||
@@ -291,6 +308,7 @@ void Tracing::s_TraceOutput(_In_z_ const char* pszMessage, ...)
|
||||
"OutputTrace",
|
||||
TraceLoggingString(szBuffer),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Output));
|
||||
|
||||
if (s_ulDebugFlag & TraceKeywords::Output)
|
||||
@@ -308,6 +326,7 @@ void Tracing::s_TraceWindowMessage(const MSG& msg)
|
||||
TraceLoggingHexUInt64(msg.wParam, "wParam"),
|
||||
TraceLoggingHexUInt64(msg.lParam, "lParam"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Input));
|
||||
}
|
||||
|
||||
@@ -329,6 +348,7 @@ void Tracing::s_TraceInputRecord(const INPUT_RECORD& inputRecord)
|
||||
TraceLoggingHexUInt8(inputRecord.Event.KeyEvent.uChar.AsciiChar, "Hex AsciiChar"),
|
||||
TraceLoggingHexUInt32(inputRecord.Event.KeyEvent.dwControlKeyState, "dwControlKeyState"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Input));
|
||||
break;
|
||||
case MOUSE_EVENT:
|
||||
@@ -341,6 +361,7 @@ void Tracing::s_TraceInputRecord(const INPUT_RECORD& inputRecord)
|
||||
TraceLoggingHexUInt32(inputRecord.Event.MouseEvent.dwControlKeyState, "dwControlKeyState"),
|
||||
TraceLoggingHexUInt32(inputRecord.Event.MouseEvent.dwEventFlags, "dwEventFlags"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Input));
|
||||
break;
|
||||
case WINDOW_BUFFER_SIZE_EVENT:
|
||||
@@ -350,6 +371,7 @@ void Tracing::s_TraceInputRecord(const INPUT_RECORD& inputRecord)
|
||||
TraceLoggingInt16(inputRecord.Event.WindowBufferSizeEvent.dwSize.X, "dwSize.X"),
|
||||
TraceLoggingInt16(inputRecord.Event.WindowBufferSizeEvent.dwSize.Y, "dwSize.Y"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Input));
|
||||
break;
|
||||
case MENU_EVENT:
|
||||
@@ -358,6 +380,7 @@ void Tracing::s_TraceInputRecord(const INPUT_RECORD& inputRecord)
|
||||
"Menu Event Input Record",
|
||||
TraceLoggingHexUInt64(inputRecord.Event.MenuEvent.dwCommandId, "dwCommandId"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Input));
|
||||
break;
|
||||
case FOCUS_EVENT:
|
||||
@@ -366,6 +389,7 @@ void Tracing::s_TraceInputRecord(const INPUT_RECORD& inputRecord)
|
||||
"Focus Event Input Record",
|
||||
TraceLoggingBool(inputRecord.Event.FocusEvent.bSetFocus, "bSetFocus"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Input));
|
||||
break;
|
||||
default:
|
||||
@@ -374,6 +398,7 @@ void Tracing::s_TraceInputRecord(const INPUT_RECORD& inputRecord)
|
||||
"Unknown Input Record",
|
||||
TraceLoggingHexUInt16(inputRecord.EventType, "EventType"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_ERROR),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE),
|
||||
TraceLoggingKeyword(TraceKeywords::Input));
|
||||
break;
|
||||
}
|
||||
@@ -393,5 +418,6 @@ void __stdcall Tracing::TraceFailure(const wil::FailureInfo& failure) noexcept
|
||||
TraceLoggingString(failure.pszModule, "Module"),
|
||||
TraceLoggingPointer(failure.returnAddress, "Site"),
|
||||
TraceLoggingString(failure.pszCode, "Code"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_ERROR));
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_ERROR),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
}
|
||||
|
||||
@@ -40,7 +40,12 @@ namespace Microsoft::Console::ErrorReporting
|
||||
if (!alreadyReported && FallbackProvider)
|
||||
{
|
||||
#pragma warning(suppress : 26477 26485 26494 26482 26446) // We don't control TraceLoggingWrite
|
||||
TraceLoggingWrite(FallbackProvider, "FallbackError", TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TraceLoggingLevel(WINEVENT_LEVEL_ERROR), CONSOLE_WIL_TRACELOGGING_FAILURE_PARAMS(failure));
|
||||
TraceLoggingWrite(FallbackProvider,
|
||||
"FallbackError",
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_ERROR),
|
||||
CONSOLE_WIL_TRACELOGGING_FAILURE_PARAMS(failure));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
|
||||
@@ -21,6 +21,34 @@
|
||||
#include "til/visualize_control_codes.h"
|
||||
#include "til/pmr.h"
|
||||
|
||||
// Use keywords on TraceLogging providers to specify the category
|
||||
// of event that we are emitting for filtering purposes.
|
||||
// The bottom 48 bits (0..47) are definable by each provider.
|
||||
// The top 16 bits are reserved by Microsoft.
|
||||
// NOTE: Any provider registering TraceLoggingOptionMicrosoftTelemetry
|
||||
// should also reserve bits 43..47 for telemetry controls.
|
||||
//
|
||||
// To ensure that providers that transmit both telemetry
|
||||
// and diagnostic information do not do excess work when only
|
||||
// a telemetry listener is attached, please set a keyword
|
||||
// on all TraceLoggingWrite statements.
|
||||
//
|
||||
// Use TIL_KEYWORD_TRACE if you are basically
|
||||
// using it as a printf-like debugging tool for super
|
||||
// deep diagnostics reasons only.
|
||||
//
|
||||
// Please do NOT leave events marked without a keyword
|
||||
// or filtering on intent will not be possible.
|
||||
//
|
||||
// See also https://osgwiki.com/wiki/TraceLogging#Semantics
|
||||
//
|
||||
// Note that Conhost had already defined some keywords
|
||||
// between bits 0..11 so be sure to not overlap those.
|
||||
// See `TraceKeywords`.
|
||||
// We will therefore try to reserve 32..42 for TIL
|
||||
// as common flags for the entire Terminal team projects.
|
||||
#define TIL_KEYWORD_TRACE 0x0000000100000000 // bit 32
|
||||
|
||||
namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
template<typename T>
|
||||
|
||||
@@ -60,11 +60,13 @@ Window::Window() :
|
||||
_fIsInFullscreen(false),
|
||||
_pSettings(nullptr),
|
||||
_hWnd(nullptr),
|
||||
_pUiaProvider(nullptr)
|
||||
_pUiaProvider(nullptr),
|
||||
_fWasMaximizedBeforeFullscreen(false),
|
||||
_dpiBeforeFullscreen(0)
|
||||
{
|
||||
ZeroMemory((void*)&_rcClientLast, sizeof(_rcClientLast));
|
||||
ZeroMemory((void*)&_rcNonFullscreenWindowSize, sizeof(_rcNonFullscreenWindowSize));
|
||||
ZeroMemory((void*)&_rcFullscreenWindowSize, sizeof(_rcFullscreenWindowSize));
|
||||
ZeroMemory((void*)&_rcWindowBeforeFullscreen, sizeof(_rcWindowBeforeFullscreen));
|
||||
ZeroMemory((void*)&_rcWorkBeforeFullscreen, sizeof(_rcWorkBeforeFullscreen));
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
@@ -1095,11 +1097,90 @@ bool Window::IsInFullscreen() const
|
||||
return _fIsInFullscreen;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Called when entering fullscreen, with the window's current monitor rect and work area.
|
||||
// - The current window position, dpi, work area, and maximized state are stored, and the
|
||||
// window is positioned to the monitor rect.
|
||||
void Window::_SetFullscreenPosition(const RECT rcMonitor, const RECT rcWork)
|
||||
{
|
||||
::GetWindowRect(GetWindowHandle(), &_rcWindowBeforeFullscreen);
|
||||
_dpiBeforeFullscreen = GetDpiForWindow(GetWindowHandle());
|
||||
_fWasMaximizedBeforeFullscreen = IsZoomed(GetWindowHandle());
|
||||
_rcWorkBeforeFullscreen = rcWork;
|
||||
|
||||
SetWindowPos(GetWindowHandle(),
|
||||
HWND_TOP,
|
||||
rcMonitor.left,
|
||||
rcMonitor.top,
|
||||
rcMonitor.right - rcMonitor.left,
|
||||
rcMonitor.bottom - rcMonitor.top,
|
||||
SWP_FRAMECHANGED);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Called when exiting fullscreen, with the window's current monitor work area.
|
||||
// - The window is restored to its previous position, migrating that previous position to the
|
||||
// window's current monitor (if the current work area or window DPI have changed).
|
||||
// - A fullscreen window's monitor can be changed by win+shift+left/right hotkeys or monitor
|
||||
// topology changes (for example unplugging a monitor or disconnecting a remote session).
|
||||
void Window::_RestoreFullscreenPosition(const RECT rcWork)
|
||||
{
|
||||
// If the window was previously maximized, re-maximize the window.
|
||||
if (_fWasMaximizedBeforeFullscreen)
|
||||
{
|
||||
ShowWindow(GetWindowHandle(), SW_SHOWMAXIMIZED);
|
||||
SetWindowPos(GetWindowHandle(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Start with the stored window position.
|
||||
RECT rcRestore = _rcWindowBeforeFullscreen;
|
||||
|
||||
// If the window DPI has changed, re-size the stored position by the change in DPI. This
|
||||
// ensures the window restores to the same logical size (even if to a monitor with a different
|
||||
// DPI/ scale factor).
|
||||
UINT dpiWindow = GetDpiForWindow(GetWindowHandle());
|
||||
rcRestore.right = rcRestore.left + MulDiv(rcRestore.right - rcRestore.left, dpiWindow, _dpiBeforeFullscreen);
|
||||
rcRestore.bottom = rcRestore.top + MulDiv(rcRestore.bottom - rcRestore.top, dpiWindow, _dpiBeforeFullscreen);
|
||||
|
||||
// Offset the stored position by the difference in work area.
|
||||
OffsetRect(&rcRestore,
|
||||
rcWork.left - _rcWorkBeforeFullscreen.left,
|
||||
rcWork.top - _rcWorkBeforeFullscreen.top);
|
||||
|
||||
// Enforce that our position is entirely within the bounds of our work area.
|
||||
// Prefer the top-left be on-screen rather than bottom-right (right before left, bottom before top).
|
||||
if (rcRestore.right > rcWork.right)
|
||||
{
|
||||
OffsetRect(&rcRestore, rcWork.right - rcRestore.right, 0);
|
||||
}
|
||||
if (rcRestore.left < rcWork.left)
|
||||
{
|
||||
OffsetRect(&rcRestore, rcWork.left - rcRestore.left, 0);
|
||||
}
|
||||
if (rcRestore.bottom > rcWork.bottom)
|
||||
{
|
||||
OffsetRect(&rcRestore, 0, rcWork.bottom - rcRestore.bottom);
|
||||
}
|
||||
if (rcRestore.top < rcWork.top)
|
||||
{
|
||||
OffsetRect(&rcRestore, 0, rcWork.top - rcRestore.top);
|
||||
}
|
||||
|
||||
// Show the window at the computed position.
|
||||
SetWindowPos(GetWindowHandle(),
|
||||
HWND_TOP,
|
||||
rcRestore.left,
|
||||
rcRestore.top,
|
||||
rcRestore.right - rcRestore.left,
|
||||
rcRestore.bottom - rcRestore.top,
|
||||
SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
|
||||
}
|
||||
|
||||
void Window::SetIsFullscreen(const bool fFullscreenEnabled)
|
||||
{
|
||||
// It is possible to enter SetIsFullScreen even if we're already in full screen.
|
||||
// Use the old is in fullscreen flag to gate checks that rely on the current state.
|
||||
bool fOldIsInFullscreen = _fIsInFullscreen;
|
||||
const bool fChangingFullscreen = (fFullscreenEnabled != _fIsInFullscreen);
|
||||
_fIsInFullscreen = fFullscreenEnabled;
|
||||
|
||||
HWND const hWnd = GetWindowHandle();
|
||||
@@ -1135,48 +1216,30 @@ void Window::SetIsFullscreen(const bool fFullscreenEnabled)
|
||||
}
|
||||
SetWindowLongW(hWnd, GWL_EXSTYLE, dwExWindowStyle);
|
||||
|
||||
_BackupWindowSizes(fOldIsInFullscreen);
|
||||
_ApplyWindowSize();
|
||||
}
|
||||
|
||||
void Window::_BackupWindowSizes(const bool fCurrentIsInFullscreen)
|
||||
{
|
||||
if (_fIsInFullscreen)
|
||||
// Only change the window position if changing fullscreen state.
|
||||
if (fChangingFullscreen)
|
||||
{
|
||||
// Note: the current window size depends on the current state of the window.
|
||||
// So don't back it up if we're already in full screen.
|
||||
if (!fCurrentIsInFullscreen)
|
||||
{
|
||||
_rcNonFullscreenWindowSize = GetWindowRect();
|
||||
}
|
||||
// Get the monitor info for the window's current monitor.
|
||||
MONITORINFO mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(MonitorFromWindow(GetWindowHandle(), MONITOR_DEFAULTTONEAREST), &mi);
|
||||
|
||||
// get and back up the current monitor's size
|
||||
HMONITOR const hCurrentMonitor = MonitorFromWindow(GetWindowHandle(), MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO currMonitorInfo;
|
||||
currMonitorInfo.cbSize = sizeof(currMonitorInfo);
|
||||
if (GetMonitorInfo(hCurrentMonitor, &currMonitorInfo))
|
||||
if (_fIsInFullscreen)
|
||||
{
|
||||
_rcFullscreenWindowSize = currMonitorInfo.rcMonitor;
|
||||
// Store the window's current position and size the window to the monitor.
|
||||
_SetFullscreenPosition(mi.rcMonitor, mi.rcWork);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore the stored window position.
|
||||
_RestoreFullscreenPosition(mi.rcWork);
|
||||
|
||||
SCREEN_INFORMATION& siAttached = GetScreenInfo();
|
||||
siAttached.MakeCurrentCursorVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::_ApplyWindowSize()
|
||||
{
|
||||
const RECT rcNewSize = _fIsInFullscreen ? _rcFullscreenWindowSize : _rcNonFullscreenWindowSize;
|
||||
|
||||
SetWindowPos(GetWindowHandle(),
|
||||
HWND_TOP,
|
||||
rcNewSize.left,
|
||||
rcNewSize.top,
|
||||
RECT_WIDTH(&rcNewSize),
|
||||
RECT_HEIGHT(&rcNewSize),
|
||||
SWP_FRAMECHANGED);
|
||||
|
||||
SCREEN_INFORMATION& siAttached = GetScreenInfo();
|
||||
siAttached.MakeCurrentCursorVisible();
|
||||
}
|
||||
|
||||
void Window::ToggleFullscreen()
|
||||
{
|
||||
SetIsFullscreen(!IsInFullscreen());
|
||||
|
||||