-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use feature markers during terminal-by-default handoff #13160
Conversation
59d45c9
to
afec10f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, this all looks like it'll work Terminal-side, and conhost side. My only recommendation would be add more comments. A lot of this defterm stuff is hard to parse, so more comments never hurt.
The code is good enough though, so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Thanks!
Dustin wanted to take a look at this, so I'm leaving it unmerged for now :) |
@msftbot make sure @DHowett signs off on this |
Hello @carlos-zamora! Because you've given me some instructions on how to help merge this pull request, I'll be modifying my merge approach. Here's how I understand your requirements for merging this pull request:
If this doesn't seem right to you, you can tell me to cancel these instructions and use the auto-merge policy that has been configured for this repository. Try telling me "forget everything I just told you". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chatted with Leonard & we need a slightly different solution :)
I redid the entire thing.
I've rewritten this PR, but haven't tested it yet and so converted this PR to a Draft. |
This comment was marked as outdated.
This comment was marked as outdated.
79ddc66
to
86a1863
Compare
fe26551
to
7c92e62
Compare
7c92e62
to
89b4739
Compare
d754068
to
33a69fe
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I read over this all, it makes sense to me. I again left notes as I went - my nit again is that all this defterm stuff is already hard to parse so more comments is always better.
@@ -93,7 +93,7 @@ | |||
|
|||
<Grid.RowDefinitions> | |||
<!-- profile name --> | |||
<RowDefinition Height="*" /> | |||
<RowDefinition Height="20" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: is this redundant with the Height="20"
on the Name
TextBlock
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately we only get the layout in the screenshot above, by specifying the height explicitly twice. The reason is that the flyout (and only the flyout) seemingly doesn't respect the visibility state of the two TextBlock
s. Due to that the dropdown box will have the correct height (1 line high) but the flyout list will be 2 lines high, even with both TextBlock
s collapsed. I'm not entirely sure how such a bug can occur, but it does. 😄
std::pair<std::vector<Model::DefaultTerminal>, Model::DefaultTerminal> result{ {}, nullptr }; | ||
til::latch latch{ 1 }; | ||
|
||
std::ignore = [&]() -> winrt::fire_and_forget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I low key really love this "go do something on a backgrouund thread" lambda, without needing to make a whole function declaration for it.
It's like a sneaky way of doing a IAsyncOperation
without also making this method async, and letting us return a non winrt type. neato.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But we're not using extractValueFromTaskWithoutMainThreadAwait
... because... it's just a static helper in the other file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extractValueFromTaskWithoutMainThreadAwait
expects an (asynchronous) Task which can be co_await
ed, but this code executes a synchronous function on a background task instead.
@@ -61,9 +61,11 @@ static auto extractValueFromTaskWithoutMainThreadAwait(TTask&& task) -> decltype | |||
til::latch latch{ 1 }; | |||
|
|||
const auto _ = [&]() -> winrt::fire_and_forget { | |||
const auto cleanup = wil::scope_exit([&]() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure I understand why this moved. Just in case task
throws?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I realized this mistake when I wrote the code for CascadiaSettings.cpp
and wanted to fix extractValueFromTaskWithoutMainThreadAwait
as well.
@@ -47,7 +47,7 @@ namespace Microsoft::Console::Internal | |||
|
|||
namespace DefaultApp | |||
{ | |||
[[nodiscard]] HRESULT CheckDefaultAppPolicy(bool& isEnabled) noexcept; | |||
[[nodiscard]] HRESULT CheckShouldTerminalBeDefault(bool& isEnabled) noexcept; | |||
[[nodiscard]] bool CheckDefaultAppPolicy() noexcept; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC if we change the signature of these methods, we'll have to update the internal-only versions as well, FYI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep! I felt like this made writing the code more comfortable and noticed that the internal code never returns anything but S_OK
anyways.
if (Globals.defaultTerminalMarkerCheckRequired) | ||
{ | ||
::Microsoft::WRL::ComPtr<IDefaultTerminalMarker> marker; | ||
if (FAILED(handoff.As(&marker))) | ||
{ | ||
Globals.delegationPair = DelegationConfig::ConhostDelegationPair; | ||
Globals.defaultTerminalMarkerCheckRequired = false; | ||
return; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the new section
&bytesNeeded); | ||
|
||
if (NTSTATUS_FROM_WIN32(ERROR_SUCCESS) != result) | ||
if (values[0] == CLSID_Default || values[1] == CLSID_Default) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
notes: if either was missing or failed to parse, use {default, 0, 0}
RETURN_IF_FAILED(IIDFromString(buffer.get(), &iid)); | ||
|
||
return S_OK; | ||
if (values[0] == CLSID_Conhost || values[1] == CLSID_Conhost) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was the saved value SPECIFICALLY conhost? then return that
oh ho ho so I see, this is where we're being tricky now. Now conhost isn't {0}, it's got it's own GUID now. That makes sense.
|
||
vec.push_back(useInbox); | ||
|
||
auto coinit = wil::CoInitializeEx(COINIT_APARTMENTTHREADED); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We pretty sure the propsheet initializes COM itself? Note that the propsheet can get loaded outside of the context of conhost, just by right-clicking on a .lnk
to a commandline application.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just moved the initialization one call up so that we don't have to do this twice.
src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
Outdated
Show resolved
Hide resolved
When #13160 introduced a new interface to the IConsoleHandoff idl, it changed midl's RPC proxy stub lookup algorithm from a direct GUID comparison to an unrolled binary search. Now, that would ordinarily not be a problem... However, in #11610, we took a shortcut and replaced `memcmp` -- used only by RPC for GUID comparison -- with a direct GUID-only equality comparator. This worked totally fine, and ordinarily would not be a problem... The unrolled binary search unfortunately _relies on memcmp's contract_: it uses memcmp to match against a fully sorted set. Our memcmp only returned 0 or 1 (equal or not), and it knew nothing about ordering. When a package that contains a PackagedCOM proxy stub is installed, it is selected as the primary proxy stub for any interfaces it can proxy. After all, interfaces are immutable, so it doesn't matter whose proxy you're using. Now, given that we installed a *broken* proxy... *all* IIDs that got whacked by our memcmp issue broke for every consumer. To fix it: instead of implementing memcmp ourselves, we're just going to take a page out of WinAppSDK's book and link this binary using the "Hybrid CRT" model. It will statically link any parts of the STL it uses (none) and dynamically link the ucrt (which is guaranteed to be present on Windows.) Sure, the binary size goes up from 8k to 24k, but... the cost is never having to worry about this again. Closes #13251
If we want to make Windows Terminal the default terminal under Windows, we'll have to make conhost "handoff" incoming connections by default. But this poses a problem: How can the seldomly updated conhost know whether the routinely updated Windows Terminal version is actually willing to accept such handoffs by default (it might be unwilling due to bugs, etc.)? This commit solves the issue by introducing: * A marker interface (`IDefaultTerminalMarker`): If it exists, Windows Terminal indicates its willingness to accept the handoff. * Turning the all-0 GUID from being synonymous for conhost, to being synonymous for "Let Windows decide". Without this we wouldn't be able to differentiate between users who consciously chose conhost as their default terminal, vs. users who want the standard behavior. Testing fallback behavior: * Install "Terminal" 1.13 * Delete the 2 keys below `HKCU\Console\%%Startup` * Enable `Feature_AttemptHandoff` in `features.xml` Return `true` from `DefaultApp::CheckShouldTerminalBeDefault` * Replace `conhost.exe` and `console.dll` with `sfpcopy` after building * Launching `cmd.exe` launches as a conhost window ✅ (because "Terminal" 1.13 lacks the marker interface) * Open properties page in `conhost.exe` "Let Windows decide" is select by default ✅ * Changing the selection writes the new value ✅ Testing the new behavior: * Delete the 2 keys below `HKCU\Console\%%Startup` * Enable `Feature_AttemptHandoff` in `features.xml` Return `true` from `DefaultApp::CheckShouldTerminalBeDefault` * Use `CLSID_WindowsTerminalConsoleDev` and `CLSID_WindowsTerminalTerminalDev` for the initialization of `TerminalDelegationPair` * Replace `conhost.exe` and `console.dll` with `sfpcopy` after building * Deploy the "Terminal Dev" package * Launching `cmd.exe` launches "Terminal Dev" ✅ (because "Terminal Dev" has the marker interface) * Open the settings tab "Let Windows decide" is select by default ✅ * Changing the selection and saving writes the new value ✅ (cherry picked from commit 1b81c65) Service-Card-Id: 82925080 Service-Version: Inbox
🎉 Handy links: |
🎉 Handy links: |
If we want to make Windows Terminal the default terminal under Windows,
we'll have to make conhost "handoff" incoming connections by default.
But this poses a problem: How can the seldomly updated conhost know
whether the routinely updated Windows Terminal version is actually willing
to accept such handoffs by default (it might be unwilling due to bugs, etc.)?
This commit solves the issue by introducing:
IDefaultTerminalMarker
): If it exists,Windows Terminal indicates its willingness to accept the handoff.
to being synonymous for "Let Windows decide". Without this we wouldn't
be able to differentiate between users who consciously chose conhost
as their default terminal, vs. users who want the standard behavior.
Validation Steps Performed
Testing fallback behavior:
HKCU\Console\%%Startup
Feature_AttemptHandoff
infeatures.xml
Return
true
fromDefaultApp::CheckShouldTerminalBeDefault
conhost.exe
andconsole.dll
withsfpcopy
after buildingcmd.exe
launches as a conhost window ✅(because "Terminal" 1.13 lacks the marker interface)
conhost.exe
"Let Windows decide" is select by default ✅
Testing the new behavior:
HKCU\Console\%%Startup
Feature_AttemptHandoff
infeatures.xml
Return
true
fromDefaultApp::CheckShouldTerminalBeDefault
CLSID_WindowsTerminalConsoleDev
andCLSID_WindowsTerminalTerminalDev
for the initialization of
TerminalDelegationPair
conhost.exe
andconsole.dll
withsfpcopy
after buildingcmd.exe
launches "Terminal Dev" ✅(because "Terminal Dev" has the marker interface)
"Let Windows decide" is select by default ✅