From 6295c8cc45379b2bc782f1cd64378c9b33441896 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 5 Oct 2021 10:28:24 -0500 Subject: [PATCH 01/71] Fix the tab color, part III (#11413) I've had a hard time with the tab colors this week. Turns out that setting the background to nullptr will make the tabviewitem invisible to hit tests. `Transparent`, on the other hand, is totally valid, and the expected default. Tabs as of this commit: ![tab-color-fix-3](https://user-images.githubusercontent.com/18356694/135915272-ff90b28b-f260-493e-bf0b-3450b4702dce.gif) ## PR Checklist * [x] Closes #11382 * [x] I work here This low-key reverts a bit of #11369, which fixed #11294, which regressed in #11240 --- src/cascadia/TerminalApp/TerminalTab.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index aaf8768cd..eb223e0ab 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1461,15 +1461,10 @@ namespace winrt::TerminalApp::implementation // when the TabViewItem is unselected. So we still need to set the other // properties ourselves. // - // GH#11294: DESPITE the fact that there's a Background() API that we - // could just call like: - // - // TabViewItem().Background(deselectedTabBrush); - // - // We actually can't, because it will make the part of the tab that - // doesn't contain the text totally transparent to hit tests. So we - // actually _do_ still need to set TabViewItemHeaderBackground manually. - TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackground"), deselectedTabBrush); + // In GH#11294 we thought we'd still need to set + // TabViewItemHeaderBackground manually, but GH#11382 discovered that + // Background() was actually okay after all. + TabViewItem().Background(deselectedTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), hoverTabBrush); TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPressed"), selectedTabBrush); @@ -1536,6 +1531,11 @@ namespace winrt::TerminalApp::implementation } } + // GH#11382 DON'T set the background to null. If you do that, then the + // tab won't be hit testable at all. Transparent, however, is a totally + // valid hit test target. That makes sense. + TabViewItem().Background(WUX::Media::SolidColorBrush{ Windows::UI::Colors::Transparent() }); + _RefreshVisualState(); _colorCleared(); } From 0b552e1ae8802ec0b384550408e9ebfd7af3029b Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Tue, 5 Oct 2021 20:21:03 +0200 Subject: [PATCH 02/71] Fix failing TestHostApp unit tests (#11394) This commit fixes various failing TestHostApp unit tests. Most of these broke as part of 168d28b (#11184). ## PR Checklist * [x] Closes #11339 * [x] I work here * [x] Tests added/passed --- .../DeserializationTests.cpp | 2 +- .../LocalTests_SettingsModel/ProfileTests.cpp | 15 +- .../SerializationTests.cpp | 54 +++---- .../CommandlineTest.cpp | 10 +- .../LocalTests_TerminalApp/SettingsTests.cpp | 152 +++++++++++++----- 5 files changed, 161 insertions(+), 72 deletions(-) diff --git a/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp index 7f6638954..ea603c942 100644 --- a/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/DeserializationTests.cpp @@ -1092,7 +1092,7 @@ namespace SettingsModelLocalTests }, { "name": "profile1", - "guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}", + "guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}", "source": "Terminal.App.UnitTest.1", "historySize": 2222 }, diff --git a/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp b/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp index 54c405592..ee42b89a4 100644 --- a/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp @@ -300,6 +300,17 @@ namespace SettingsModelLocalTests // the GUID generated for a dynamic profile (with a source) is different // than that of a profile without a source. + static constexpr std::string_view inboxSettings{ R"({ + "profiles": [ + { + "name" : "profile0", + "source": "Terminal.App.UnitTest.0" + }, + { + "name" : "profile1" + } + ] + })" }; static constexpr std::string_view userSettings{ R"({ "profiles": [ { @@ -312,9 +323,9 @@ namespace SettingsModelLocalTests ] })" }; - const auto settings = winrt::make_self(userSettings, DefaultJson); + const auto settings = winrt::make_self(userSettings, inboxSettings); - VERIFY_ARE_EQUAL(4u, settings->AllProfiles().Size()); + VERIFY_ARE_EQUAL(3u, settings->AllProfiles().Size()); VERIFY_ARE_EQUAL(L"profile0", settings->AllProfiles().GetAt(0).Name()); VERIFY_IS_TRUE(settings->AllProfiles().GetAt(0).HasGuid()); diff --git a/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp b/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp index e538967f9..10214b861 100644 --- a/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/SerializationTests.cpp @@ -53,7 +53,7 @@ namespace SettingsModelLocalTests // Return Value: // - the JsonObject representing this instance template - void RoundtripTest(const std::string& jsonString) + void RoundtripTest(const std::string_view& jsonString) { const auto json{ VerifyParseSucceeded(jsonString) }; const auto settings{ T::FromJson(json) }; @@ -69,7 +69,7 @@ namespace SettingsModelLocalTests void SerializationTests::GlobalSettings() { - const std::string globalsString{ R"( + static constexpr std::string_view globalsString{ R"( { "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", @@ -105,7 +105,7 @@ namespace SettingsModelLocalTests "actions": [] })" }; - const std::string smallGlobalsString{ R"( + static constexpr std::string_view smallGlobalsString{ R"( { "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", "actions": [] @@ -117,7 +117,7 @@ namespace SettingsModelLocalTests void SerializationTests::Profile() { - const std::string profileString{ R"( + static constexpr std::string_view profileString{ R"( { "name": "Windows PowerShell", "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", @@ -152,7 +152,7 @@ namespace SettingsModelLocalTests "selectionBackground": "#CCAABB", "useAcrylic": false, - "acrylicOpacity": 0.5, + "opacity": 50, "backgroundImage": "made_you_look.jpeg", "backgroundImageStretchMode": "uniformToFill", @@ -167,7 +167,7 @@ namespace SettingsModelLocalTests "experimental.retroTerminalEffect": false })" }; - const std::string smallProfileString{ R"( + static constexpr std::string_view smallProfileString{ R"( { "name": "Custom Profile" })" }; @@ -175,7 +175,7 @@ namespace SettingsModelLocalTests // Setting "tabColor" to null tests two things: // - null should count as an explicit user-set value, not falling back to the parent's value // - null should be acceptable even though we're working with colors - const std::string weirdProfileString{ R"( + static constexpr std::string_view weirdProfileString{ R"( { "guid" : "{8b039d4d-77ca-5a83-88e1-dfc8e895a127}", "name": "Weird Profile", @@ -192,7 +192,7 @@ namespace SettingsModelLocalTests void SerializationTests::ColorScheme() { - const std::string schemeString{ R"({ + static constexpr std::string_view schemeString{ R"({ "name": "Campbell", "cursorColor": "#FFFFFF", @@ -225,56 +225,56 @@ namespace SettingsModelLocalTests void SerializationTests::Actions() { // simple command - const std::string actionsString1{ R"([ + static constexpr std::string_view actionsString1{ R"([ { "command": "paste" } ])" }; // complex command - const std::string actionsString2A{ R"([ + static constexpr std::string_view actionsString2A{ R"([ { "command": { "action": "setTabColor" } } ])" }; - const std::string actionsString2B{ R"([ + static constexpr std::string_view actionsString2B{ R"([ { "command": { "action": "setTabColor", "color": "#112233" } } ])" }; - const std::string actionsString2C{ R"([ + static constexpr std::string_view actionsString2C{ R"([ { "command": { "action": "copy" } }, { "command": { "action": "copy", "singleLine": true, "copyFormatting": "html" } } ])" }; // simple command with key chords - const std::string actionsString3{ R"([ + static constexpr std::string_view actionsString3{ R"([ { "command": "toggleAlwaysOnTop", "keys": "ctrl+a" }, { "command": "toggleAlwaysOnTop", "keys": "ctrl+b" } ])" }; // complex command with key chords - const std::string actionsString4A{ R"([ + static constexpr std::string_view actionsString4A{ R"([ { "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+c" }, { "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+d" } ])" }; - const std::string actionsString4B{ R"([ + static constexpr std::string_view actionsString4B{ R"([ { "command": { "action": "findMatch", "direction": "next" }, "keys": "ctrl+shift+s" }, { "command": { "action": "findMatch", "direction": "prev" }, "keys": "ctrl+shift+r" } ])" }; // command with name and icon and multiple key chords - const std::string actionsString5{ R"([ + static constexpr std::string_view actionsString5{ R"([ { "icon": "image.png", "name": "Scroll To Top Name", "command": "scrollToTop", "keys": "ctrl+e" }, { "command": "scrollToTop", "keys": "ctrl+f" } ])" }; // complex command with new terminal args - const std::string actionsString6{ R"([ + static constexpr std::string_view actionsString6{ R"([ { "command": { "action": "newTab", "index": 0 }, "keys": "ctrl+g" }, ])" }; // complex command with meaningful null arg - const std::string actionsString7{ R"([ + static constexpr std::string_view actionsString7{ R"([ { "command": { "action": "renameWindow", "name": null }, "keys": "ctrl+h" } ])" }; // nested command - const std::string actionsString8{ R"([ + static constexpr std::string_view actionsString8{ R"([ { "name": "Change font size...", "commands": [ @@ -286,7 +286,7 @@ namespace SettingsModelLocalTests ])" }; // iterable command - const std::string actionsString9A{ R"([ + static constexpr std::string_view actionsString9A{ R"([ { "name": "New tab", "commands": [ @@ -299,7 +299,7 @@ namespace SettingsModelLocalTests ] } ])" }; - const std::string actionsString9B{ R"([ + static constexpr std::string_view actionsString9B{ R"([ { "commands": [ @@ -315,7 +315,7 @@ namespace SettingsModelLocalTests "name": "Send Input ..." } ])" }; - const std::string actionsString9C{ R""([ + static constexpr std::string_view actionsString9C{ R""([ { "commands": [ @@ -338,7 +338,7 @@ namespace SettingsModelLocalTests "name": "Send Input (Evil) ..." } ])"" }; - const std::string actionsString9D{ R""([ + static constexpr std::string_view actionsString9D{ R""([ { "command": { @@ -352,7 +352,7 @@ namespace SettingsModelLocalTests ])"" }; // unbound command - const std::string actionsString10{ R"([ + static constexpr std::string_view actionsString10{ R"([ { "command": "unbound", "keys": "ctrl+c" } ])" }; @@ -395,7 +395,7 @@ namespace SettingsModelLocalTests void SerializationTests::CascadiaSettings() { - const std::string settingsString{ R"({ + static constexpr std::string_view settingsString{ R"({ "$help" : "https://aka.ms/terminal-documentation", "$schema" : "https://aka.ms/terminal-profiles-schema", "defaultProfile": "{61c54bbd-1111-5271-96e7-009a87ff44bf}", @@ -465,7 +465,7 @@ namespace SettingsModelLocalTests void SerializationTests::LegacyFontSettings() { - const std::string profileString{ R"( + static constexpr std::string_view profileString{ R"( { "name": "Profile with legacy font settings", @@ -474,7 +474,7 @@ namespace SettingsModelLocalTests "fontWeight": "normal" })" }; - const std::string expectedOutput{ R"( + static constexpr std::string_view expectedOutput{ R"( { "name": "Profile with legacy font settings", diff --git a/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp b/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp index a9975b661..0d63043de 100644 --- a/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp +++ b/src/cascadia/LocalTests_TerminalApp/CommandlineTest.cpp @@ -1031,9 +1031,11 @@ namespace TerminalAppLocalTests // The first action is going to always be a new-tab action VERIFY_ARE_EQUAL(ShortcutAction::NewTab, appArgs._startupActions.at(0).Action()); - auto actionAndArgs = appArgs._startupActions.at(1); + const auto actionAndArgs = appArgs._startupActions.at(1); VERIFY_ARE_EQUAL(ShortcutAction::NextTab, actionAndArgs.Action()); - VERIFY_IS_NULL(actionAndArgs.Args()); + VERIFY_IS_NOT_NULL(actionAndArgs.Args()); + const auto myArgs = actionAndArgs.Args().as(); + VERIFY_ARE_EQUAL(TabSwitcherMode::Disabled, myArgs.SwitcherMode().Value()); } { AppCommandlineArgs appArgs{}; @@ -1047,7 +1049,9 @@ namespace TerminalAppLocalTests auto actionAndArgs = appArgs._startupActions.at(1); VERIFY_ARE_EQUAL(ShortcutAction::PrevTab, actionAndArgs.Action()); - VERIFY_IS_NULL(actionAndArgs.Args()); + VERIFY_IS_NOT_NULL(actionAndArgs.Args()); + const auto myArgs = actionAndArgs.Args().as(); + VERIFY_ARE_EQUAL(TabSwitcherMode::Disabled, myArgs.SwitcherMode().Value()); } { AppCommandlineArgs appArgs{}; diff --git a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp index fd7a8e446..f2c6fac9d 100644 --- a/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/SettingsTests.cpp @@ -16,6 +16,31 @@ using namespace winrt::Microsoft::Terminal::Control; namespace TerminalAppLocalTests { + static constexpr std::wstring_view inboxSettings{ LR"({ + "schemes": [{ + "name": "Campbell", + "foreground": "#CCCCCC", + "background": "#0C0C0C", + "cursorColor": "#FFFFFF", + "black": "#0C0C0C", + "red": "#C50F1F", + "green": "#13A10E", + "yellow": "#C19C00", + "blue": "#0037DA", + "purple": "#881798", + "cyan": "#3A96DD", + "white": "#CCCCCC", + "brightBlack": "#767676", + "brightRed": "#E74856", + "brightGreen": "#16C60C", + "brightYellow": "#F9F1A5", + "brightBlue": "#3B78FF", + "brightPurple": "#B4009E", + "brightCyan": "#61D6D6", + "brightWhite": "#F2F2F2" + }] + })" }; + // TODO:microsoft/terminal#3838: // Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for // an updated TAEF that will let us install framework packages when the test @@ -107,11 +132,10 @@ namespace TerminalAppLocalTests "iterateOn": "profiles", "command": { "action": "splitPane", "profile": "${profile.name}" } }, - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + ] })" }; - CascadiaSettings settings{ settingsJson, {} }; + CascadiaSettings settings{ settingsJson, inboxSettings }; VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); @@ -231,11 +255,10 @@ namespace TerminalAppLocalTests "iterateOn": "profiles", "command": { "action": "splitPane", "profile": "${profile.name}" } }, - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + ] })" }; - CascadiaSettings settings{ settingsJson, {} }; + CascadiaSettings settings{ settingsJson, inboxSettings }; VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); @@ -357,11 +380,10 @@ namespace TerminalAppLocalTests "iterateOn": "profiles", "command": { "action": "splitPane", "profile": "${profile.name}" } }, - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + ] })" }; - CascadiaSettings settings{ settingsJson, {} }; + CascadiaSettings settings{ settingsJson, inboxSettings }; VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); @@ -495,11 +517,10 @@ namespace TerminalAppLocalTests } ] }, - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + ] })" }; - CascadiaSettings settings{ settingsJson, {} }; + CascadiaSettings settings{ settingsJson, inboxSettings }; VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); @@ -590,11 +611,10 @@ namespace TerminalAppLocalTests }, ] }, - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + ] })" }; - CascadiaSettings settings{ settingsJson, {} }; + CascadiaSettings settings{ settingsJson, inboxSettings }; VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); @@ -714,11 +734,10 @@ namespace TerminalAppLocalTests { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "down" } } ] } - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + ] })" }; - CascadiaSettings settings{ settingsJson, {} }; + CascadiaSettings settings{ settingsJson, inboxSettings }; VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); @@ -851,11 +870,10 @@ namespace TerminalAppLocalTests } ] } - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + ] })" }; - CascadiaSettings settings{ settingsJson, {} }; + CascadiaSettings settings{ settingsJson, inboxSettings }; VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); @@ -954,11 +972,10 @@ namespace TerminalAppLocalTests } ] } - ], - "schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors. + ] })" }; - CascadiaSettings settings{ settingsJson, {} }; + CascadiaSettings settings{ settingsJson, inboxSettings }; VERIFY_ARE_EQUAL(0u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); @@ -1085,9 +1102,72 @@ namespace TerminalAppLocalTests } ], "schemes": [ - { "name": "scheme_0" }, - { "name": "scheme_1" }, - { "name": "scheme_2" }, + { + "name": "Campbell", + "foreground": "#CCCCCC", + "background": "#0C0C0C", + "cursorColor": "#FFFFFF", + "black": "#0C0C0C", + "red": "#C50F1F", + "green": "#13A10E", + "yellow": "#C19C00", + "blue": "#0037DA", + "purple": "#881798", + "cyan": "#3A96DD", + "white": "#CCCCCC", + "brightBlack": "#767676", + "brightRed": "#E74856", + "brightGreen": "#16C60C", + "brightYellow": "#F9F1A5", + "brightBlue": "#3B78FF", + "brightPurple": "#B4009E", + "brightCyan": "#61D6D6", + "brightWhite": "#F2F2F2" + }, + { + "name": "Campbell PowerShell", + "foreground": "#CCCCCC", + "background": "#012456", + "cursorColor": "#FFFFFF", + "black": "#0C0C0C", + "red": "#C50F1F", + "green": "#13A10E", + "yellow": "#C19C00", + "blue": "#0037DA", + "purple": "#881798", + "cyan": "#3A96DD", + "white": "#CCCCCC", + "brightBlack": "#767676", + "brightRed": "#E74856", + "brightGreen": "#16C60C", + "brightYellow": "#F9F1A5", + "brightBlue": "#3B78FF", + "brightPurple": "#B4009E", + "brightCyan": "#61D6D6", + "brightWhite": "#F2F2F2" + }, + { + "name": "Vintage", + "foreground": "#C0C0C0", + "background": "#000000", + "cursorColor": "#FFFFFF", + "black": "#000000", + "red": "#800000", + "green": "#008000", + "yellow": "#808000", + "blue": "#000080", + "purple": "#800080", + "cyan": "#008080", + "white": "#C0C0C0", + "brightBlack": "#808080", + "brightRed": "#FF0000", + "brightGreen": "#00FF00", + "brightYellow": "#FFFF00", + "brightBlue": "#0000FF", + "brightPurple": "#FF00FF", + "brightCyan": "#00FFFF", + "brightWhite": "#FFFFFF" + } ], "actions": [ { @@ -1100,10 +1180,6 @@ namespace TerminalAppLocalTests CascadiaSettings settings{ settingsJson, {} }; - // Since at least one profile does not reference a color scheme, - // we add a warning saying "the color scheme is unknown" - VERIFY_ARE_EQUAL(1u, settings.Warnings().Size()); - VERIFY_ARE_EQUAL(3u, settings.ActiveProfiles().Size()); auto nameMap{ settings.ActionMap().NameMap() }; @@ -1130,8 +1206,6 @@ namespace TerminalAppLocalTests auto expandedCommands = winrt::TerminalApp::implementation::TerminalPage::_ExpandCommands(nameMap, settings.ActiveProfiles().GetView(), settings.GlobalSettings().ColorSchemes()); _logCommandNames(expandedCommands.GetView()); - // This is the same warning as above - VERIFY_ARE_EQUAL(1u, settings.Warnings().Size()); VERIFY_ARE_EQUAL(3u, expandedCommands.Size()); // Yes, this test is testing splitPane with profiles named after each @@ -1139,7 +1213,7 @@ namespace TerminalAppLocalTests // just easy tests to write. { - auto command = expandedCommands.Lookup(L"iterable command scheme_0"); + auto command = expandedCommands.Lookup(L"iterable command Campbell"); VERIFY_IS_NOT_NULL(command); auto actionAndArgs = command.ActionAndArgs(); VERIFY_IS_NOT_NULL(actionAndArgs); @@ -1153,11 +1227,11 @@ namespace TerminalAppLocalTests VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"scheme_0", realArgs.TerminalArgs().Profile()); + VERIFY_ARE_EQUAL(L"Campbell", realArgs.TerminalArgs().Profile()); } { - auto command = expandedCommands.Lookup(L"iterable command scheme_1"); + auto command = expandedCommands.Lookup(L"iterable command Campbell PowerShell"); VERIFY_IS_NOT_NULL(command); auto actionAndArgs = command.ActionAndArgs(); VERIFY_IS_NOT_NULL(actionAndArgs); @@ -1171,11 +1245,11 @@ namespace TerminalAppLocalTests VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"scheme_1", realArgs.TerminalArgs().Profile()); + VERIFY_ARE_EQUAL(L"Campbell PowerShell", realArgs.TerminalArgs().Profile()); } { - auto command = expandedCommands.Lookup(L"iterable command scheme_2"); + auto command = expandedCommands.Lookup(L"iterable command Vintage"); VERIFY_IS_NOT_NULL(command); auto actionAndArgs = command.ActionAndArgs(); VERIFY_IS_NOT_NULL(actionAndArgs); @@ -1189,7 +1263,7 @@ namespace TerminalAppLocalTests VERIFY_IS_TRUE(realArgs.TerminalArgs().StartingDirectory().empty()); VERIFY_IS_TRUE(realArgs.TerminalArgs().TabTitle().empty()); VERIFY_IS_FALSE(realArgs.TerminalArgs().Profile().empty()); - VERIFY_ARE_EQUAL(L"scheme_2", realArgs.TerminalArgs().Profile()); + VERIFY_ARE_EQUAL(L"Vintage", realArgs.TerminalArgs().Profile()); } } From f7b5b5caf8bb108b450092b610171b57c701a6e0 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Wed, 6 Oct 2021 04:32:14 -0700 Subject: [PATCH 03/71] Enable DefApp hooks for stable (#11423) Uncommenting parts of stable's AppXManifest to allow defapp to work with it. --- src/cascadia/CascadiaPackage/Package.appxmanifest | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cascadia/CascadiaPackage/Package.appxmanifest b/src/cascadia/CascadiaPackage/Package.appxmanifest index db9cfe825..b73a6453b 100644 --- a/src/cascadia/CascadiaPackage/Package.appxmanifest +++ b/src/cascadia/CascadiaPackage/Package.appxmanifest @@ -74,7 +74,7 @@ Enabled="false" DisplayName="ms-resource:AppName" /> - + - + From 14d068f73b870ed43b0aaabab871d1bf1f5a5b2b Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Wed, 6 Oct 2021 04:33:05 -0700 Subject: [PATCH 04/71] Fix crash and empty action in SUI Actions Page (#11427) ## Summary of the Pull Request Fixes two issues related to SUI's Actions page: 1. Crash when adding an action and setting key chord to one that is already taken - **Cause**: the new key binding that was introduced with the "Add new" button appears in `_KeyBindingList` that we're iterating over. This has no `CurrentKeys()`, resulting in a null pointer exception. - **Fix**: null-check it 2. There's an action that appears as being nameless in the dropdown - **Cause**: The culprit seems to be `MultipleActions`. We would register it, but it wouldn't have a name, so it would appear as a nameless option. - **Fix**: if it has no name, don't register it. This is also future-proof in that any new nameless actions won't be automatically added. Closes #10981 Part of #11353 --- src/cascadia/TerminalSettingsEditor/Actions.cpp | 4 ++-- src/cascadia/TerminalSettingsModel/ActionMap.cpp | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalSettingsEditor/Actions.cpp b/src/cascadia/TerminalSettingsEditor/Actions.cpp index 4f65c8cba..8e3a06a07 100644 --- a/src/cascadia/TerminalSettingsEditor/Actions.cpp +++ b/src/cascadia/TerminalSettingsEditor/Actions.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "pch.h" @@ -369,7 +369,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { const auto kbdVM{ get_self(_KeyBindingList.GetAt(i)) }; const auto& otherKeys{ kbdVM->CurrentKeys() }; - if (keys.Modifiers() == otherKeys.Modifiers() && keys.Vkey() == otherKeys.Vkey()) + if (otherKeys && keys.Modifiers() == otherKeys.Modifiers() && keys.Vkey() == otherKeys.Vkey()) { return i; } diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.cpp b/src/cascadia/TerminalSettingsModel/ActionMap.cpp index 6472245aa..1bd4aa390 100644 --- a/src/cascadia/TerminalSettingsModel/ActionMap.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionMap.cpp @@ -94,15 +94,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation static void RegisterShortcutAction(ShortcutAction shortcutAction, std::unordered_map& list, std::unordered_set& visited) { const auto actionAndArgs{ make_self(shortcutAction) }; - if (actionAndArgs->Action() != ShortcutAction::Invalid) + /*We have a valid action.*/ + /*Check if the action was already added.*/ + if (visited.find(Hash(*actionAndArgs)) == visited.end()) { - /*We have a valid action.*/ - /*Check if the action was already added.*/ - if (visited.find(Hash(*actionAndArgs)) == visited.end()) + /*This is an action that wasn't added!*/ + /*Let's add it if it has a name.*/ + if (const auto name{ actionAndArgs->GenerateName() }; !name.empty()) { - /*This is an action that wasn't added!*/ - /*Let's add it.*/ - const auto name{ actionAndArgs->GenerateName() }; list.insert({ name, *actionAndArgs }); } } From 43ce9fda09dee47046febe28b8888581ab91a604 Mon Sep 17 00:00:00 2001 From: Carlos Zamora Date: Wed, 6 Oct 2021 04:34:53 -0700 Subject: [PATCH 05/71] Refresh frame margins when moving between monitors (#11412) ## Summary of the Pull Request Refresh the DPI and frame margins when we move the window between different DPI monitors. ## PR Checklist Closes #11367 --- src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index b4f0683fa..60dd263a2 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -310,6 +310,12 @@ void NonClientIslandWindow::OnSize(const UINT width, const UINT height) { _UpdateIslandPosition(width, height); } + + // GH#11367: We need to do this, + // otherwise the titlebar may still be partially visible + // when we move between different DPI monitors. + RefreshCurrentDPI(); + _UpdateFrameMargins(); } // Method Description: From 925b05a3b71bc7584f2637900a204ed4f72a70ec Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 6 Oct 2021 11:55:55 -0500 Subject: [PATCH 06/71] Center-align the shield with the other tab row icons (#11441) I started from here: https://github.com/microsoft/microsoft-ui-xaml/blob/9052972906c8a0a1b6cb5d5c61b27d6d27cd7f11/dev/CommonStyles/Button_themeresources_v1.xaml#L121 but adding a padding of 3 was still off by one pixel, so it's 4 now. _enhance.png_ ![image](https://user-images.githubusercontent.com/18356694/136219225-3fcffd48-79b4-4efc-a4c3-4b59f9878962.png) * [x] closes #11421 --- src/cascadia/TerminalApp/TabRowControl.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cascadia/TerminalApp/TabRowControl.xaml b/src/cascadia/TerminalApp/TabRowControl.xaml index b3b0f58c3..0cce26ef3 100644 --- a/src/cascadia/TerminalApp/TabRowControl.xaml +++ b/src/cascadia/TerminalApp/TabRowControl.xaml @@ -23,7 +23,7 @@ Date: Wed, 6 Oct 2021 18:58:09 +0200 Subject: [PATCH 07/71] Fix default terminal setting dropdown (#11430) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WinUI/XAML requires the `SelectedItem` to be member of the list of `ItemsSource`. `CascadiaSettings::DefaultTerminals()` is such an `ItemsSource` and is called every time the launch settings page is visited. It calls `DefaultTerminal::Available()` which in turn calls `Refresh()`. While the `SelectedItem` was cached in `CascadiaSettings`, the value of `DefaultTerminals()` wasn't. Thus every time the page was visited, it refreshed the `ItemsSource` list without invalidating the current `SelectedItem`. This commit prevents such accidental mishaps from occurring in the future, by moving the responsibility of caching solely to the `CascadiaSettings` class. ## PR Checklist * [x] Closes #11424 * [x] I work here * [x] Tests added/passed ## Validation Steps Performed * Navigating between SUI pages maintains the current dropdown selection ✔️ * Saving the settings saves the correct terminal at `HKCU:\Console\%%Startup` ✔️ --- .github/actions/spelling/expect/expect.txt | 5 +- .../CascadiaSettings.cpp | 37 ++++++----- .../TerminalSettingsModel/CascadiaSettings.h | 4 +- .../CascadiaSettingsSerialization.cpp | 3 +- .../TerminalSettingsModel/DefaultTerminal.cpp | 65 +++++++------------ .../TerminalSettingsModel/DefaultTerminal.h | 14 +--- .../TerminalSettingsModel/DefaultTerminal.idl | 3 - 7 files changed, 56 insertions(+), 75 deletions(-) diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt index c12609802..01dfe9d5e 100644 --- a/.github/actions/spelling/expect/expect.txt +++ b/.github/actions/spelling/expect/expect.txt @@ -189,13 +189,12 @@ cacafire callee capslock CARETBLINKINGENABLED +carlos CARRIAGERETURN cascadia cassert castsi catid -carlos -zamora cazamor CBash cbegin @@ -2724,6 +2723,7 @@ wixproj wline wlinestream wmain +wmemory WMSZ wnd WNDALLOC @@ -2850,6 +2850,7 @@ YSize YSubstantial YVIRTUALSCREEN YWalk +zamora ZCmd ZCtrl zsh diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index 9ee9fc6b1..4a9b274bf 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -5,6 +5,7 @@ #include "CascadiaSettings.h" #include "CascadiaSettings.g.cpp" +#include "DefaultTerminal.h" #include "FileUtils.h" #include @@ -844,31 +845,21 @@ bool CascadiaSettings::IsDefaultTerminalAvailable() noexcept // - // Return Value: // - an iterable collection of all available terminals that could be the default. -IObservableVector CascadiaSettings::DefaultTerminals() const noexcept +IObservableVector CascadiaSettings::DefaultTerminals() noexcept { - const auto available = DefaultTerminal::Available(); - std::vector terminals{ available.Size(), nullptr }; - available.GetMany(0, terminals); - return winrt::single_threaded_observable_vector(std::move(terminals)); + _refreshDefaultTerminals(); + return _defaultTerminals; } // Method Description: // - Returns the currently selected default terminal application. -// - DANGER! This will be null unless you've called -// CascadiaSettings::RefreshDefaultTerminals. At the time of this comment (May - -// 2021), only the Launch page in the settings UI calls that method, so this -// value is unset unless you've navigated to that page. // Arguments: // - // Return Value: // - the selected default terminal application Settings::Model::DefaultTerminal CascadiaSettings::CurrentDefaultTerminal() noexcept { - if (!_currentDefaultTerminal) - { - _currentDefaultTerminal = DefaultTerminal::Current(); - } + _refreshDefaultTerminals(); return _currentDefaultTerminal; } @@ -883,11 +874,27 @@ void CascadiaSettings::CurrentDefaultTerminal(const Model::DefaultTerminal& term _currentDefaultTerminal = terminal; } +// This function is implicitly called by DefaultTerminals/CurrentDefaultTerminal(). +// It reloads the selection of available, installed terminals and caches them. +// WinUI requires us that the `SelectedItem` of a collection is member of the list given to `ItemsSource`. +// It's thus important that _currentDefaultTerminal is a member of _defaultTerminals. +// Right now this is implicitly the case thanks to DefaultTerminal::Available(), +// but in the future it might be worthwhile to change the code to use list indices instead. +void CascadiaSettings::_refreshDefaultTerminals() +{ + if (!_defaultTerminals) + { + auto [defaultTerminals, defaultTerminal] = DefaultTerminal::Available(); + _defaultTerminals = winrt::single_threaded_observable_vector(std::move(defaultTerminals)); + _currentDefaultTerminal = std::move(defaultTerminal); + } +} + void CascadiaSettings::ExportFile(winrt::hstring path, winrt::hstring content) { try { - winrt::Microsoft::Terminal::Settings::Model::WriteUTF8FileAtomic({ path.c_str() }, til::u16u8(content)); + WriteUTF8FileAtomic({ path.c_str() }, til::u16u8(content)); } CATCH_LOG(); } diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h index d25e7373c..176600c75 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h @@ -134,7 +134,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation // defterm static bool IsDefaultTerminalAvailable() noexcept; - winrt::Windows::Foundation::Collections::IObservableVector DefaultTerminals() const noexcept; + winrt::Windows::Foundation::Collections::IObservableVector DefaultTerminals() noexcept; Model::DefaultTerminal CurrentDefaultTerminal() noexcept; void CurrentDefaultTerminal(const Model::DefaultTerminal& terminal); @@ -142,6 +142,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation static const std::filesystem::path& _settingsPath(); winrt::com_ptr _createNewProfile(const std::wstring_view& name) const; + void _refreshDefaultTerminals(); void _resolveDefaultProfile() const; @@ -164,6 +165,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation winrt::hstring _deserializationErrorMessage; // defterm + winrt::Windows::Foundation::Collections::IObservableVector _defaultTerminals{ nullptr }; Model::DefaultTerminal _currentDefaultTerminal{ nullptr }; }; } diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp index f667b9ede..6b92b99b7 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp @@ -24,6 +24,7 @@ #include "userDefaults.h" #include "ApplicationState.h" +#include "DefaultTerminal.h" #include "FileUtils.h" using namespace winrt::Microsoft::Terminal::Settings; @@ -36,8 +37,6 @@ static constexpr std::string_view ProfilesKey{ "profiles" }; static constexpr std::string_view DefaultSettingsKey{ "defaults" }; static constexpr std::string_view ProfilesListKey{ "list" }; static constexpr std::string_view SchemesKey{ "schemes" }; -static constexpr std::string_view NameKey{ "name" }; -static constexpr std::string_view GuidKey{ "guid" }; static constexpr std::wstring_view jsonExtension{ L".json" }; static constexpr std::wstring_view FragmentsSubDirectory{ L"\\Fragments" }; diff --git a/src/cascadia/TerminalSettingsModel/DefaultTerminal.cpp b/src/cascadia/TerminalSettingsModel/DefaultTerminal.cpp index 5f5079d2f..9a614baf3 100644 --- a/src/cascadia/TerminalSettingsModel/DefaultTerminal.cpp +++ b/src/cascadia/TerminalSettingsModel/DefaultTerminal.cpp @@ -10,85 +10,70 @@ using namespace winrt::Microsoft::Terminal::Settings; using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; -winrt::Windows::Foundation::Collections::IVector DefaultTerminal::_available = winrt::single_threaded_vector(); -Model::DefaultTerminal DefaultTerminal::_current = nullptr; - -DefaultTerminal::DefaultTerminal(DelegationConfig::DelegationPackage pkg) : - _pkg(pkg) +DefaultTerminal::DefaultTerminal(DelegationConfig::DelegationPackage&& pkg) : + _pkg{ pkg } { } winrt::hstring DefaultTerminal::Name() const { - static const std::wstring def{ RS_(L"InboxWindowsConsoleName") }; - return _pkg.terminal.name.empty() ? winrt::hstring{ def } : winrt::hstring{ _pkg.terminal.name }; + return _pkg.terminal.name.empty() ? winrt::hstring{ RS_(L"InboxWindowsConsoleName") } : winrt::hstring{ _pkg.terminal.name }; } winrt::hstring DefaultTerminal::Version() const { // If there's no version information... return empty string instead. - if (DelegationConfig::PkgVersion{} == _pkg.terminal.version) + const auto& version = _pkg.terminal.version; + if (DelegationConfig::PkgVersion{} == version) { return winrt::hstring{}; } - const auto name = fmt::format(L"{}.{}.{}.{}", _pkg.terminal.version.major, _pkg.terminal.version.minor, _pkg.terminal.version.build, _pkg.terminal.version.revision); - return winrt::hstring{ name }; + fmt::wmemory_buffer buffer; + fmt::format_to(buffer, L"{}.{}.{}.{}", version.major, version.minor, version.build, version.revision); + return winrt::hstring{ buffer.data(), gsl::narrow_cast(buffer.size()) }; } winrt::hstring DefaultTerminal::Author() const { - static const std::wstring def{ RS_(L"InboxWindowsConsoleAuthor") }; - return _pkg.terminal.author.empty() ? winrt::hstring{ def } : winrt::hstring{ _pkg.terminal.author }; + return _pkg.terminal.author.empty() ? winrt::hstring{ RS_(L"InboxWindowsConsoleAuthor") } : winrt::hstring{ _pkg.terminal.author }; } winrt::hstring DefaultTerminal::Icon() const { - static const std::wstring_view def{ L"\uE756" }; - return _pkg.terminal.logo.empty() ? winrt::hstring{ def } : winrt::hstring{ _pkg.terminal.logo }; + return _pkg.terminal.logo.empty() ? winrt::hstring{ L"\uE756" } : winrt::hstring{ _pkg.terminal.logo }; } -void DefaultTerminal::Refresh() +std::pair, Model::DefaultTerminal> DefaultTerminal::Available() { + // The potential of returning nullptr for defaultTerminal feels weird, but XAML can + // handle that appropriately and will select nothing as current in the dropdown. + std::vector defaultTerminals; + Model::DefaultTerminal defaultTerminal{ nullptr }; + std::vector allPackages; DelegationConfig::DelegationPackage currentPackage; - LOG_IF_FAILED(DelegationConfig::s_GetAvailablePackages(allPackages, currentPackage)); - _available.Clear(); - for (const auto& pkg : allPackages) + for (auto& pkg : allPackages) { - auto p = winrt::make(pkg); + // Be a bit careful here: We're moving pkg into the constructor. + // Afterwards it'll be invalid, so we need to cache isCurrent. + const auto isCurrent = pkg == currentPackage; + auto p = winrt::make(std::move(pkg)); - _available.Append(p); - - if (pkg == currentPackage) + if (isCurrent) { - _current = p; + defaultTerminal = p; } - } -} -winrt::Windows::Foundation::Collections::IVectorView DefaultTerminal::Available() -{ - Refresh(); - return _available.GetView(); -} - -Model::DefaultTerminal DefaultTerminal::Current() -{ - if (!_current) - { - Refresh(); + defaultTerminals.emplace_back(std::move(p)); } - // The potential of returning nullptr feels weird, but XAML can handle that appropriately - // and will select nothing as current in the dropdown. - return _current; + return { std::move(defaultTerminals), std::move(defaultTerminal) }; } void DefaultTerminal::Current(const Model::DefaultTerminal& term) { THROW_IF_FAILED(DelegationConfig::s_SetDefaultByPackage(winrt::get_self(term)->_pkg, true)); - _current = term; } diff --git a/src/cascadia/TerminalSettingsModel/DefaultTerminal.h b/src/cascadia/TerminalSettingsModel/DefaultTerminal.h index ddce7d576..19f3ae14c 100644 --- a/src/cascadia/TerminalSettingsModel/DefaultTerminal.h +++ b/src/cascadia/TerminalSettingsModel/DefaultTerminal.h @@ -19,7 +19,6 @@ Author(s): #pragma once #include "DefaultTerminal.g.h" -#include "../inc/cppwinrt_utils.h" #include "../../propslib/DelegationConfig.hpp" @@ -27,26 +26,17 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { struct DefaultTerminal : public DefaultTerminalT { - DefaultTerminal(DelegationConfig::DelegationPackage pkg); + explicit DefaultTerminal(DelegationConfig::DelegationPackage&& pkg); hstring Name() const; hstring Author() const; hstring Version() const; hstring Icon() const; - static void Refresh(); - static Windows::Foundation::Collections::IVectorView Available(); - static Model::DefaultTerminal Current(); + static std::pair, Model::DefaultTerminal> Available(); static void Current(const Model::DefaultTerminal& term); private: DelegationConfig::DelegationPackage _pkg; - static Windows::Foundation::Collections::IVector _available; - static Model::DefaultTerminal _current; }; } - -namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation -{ - BASIC_FACTORY(DefaultTerminal); -} diff --git a/src/cascadia/TerminalSettingsModel/DefaultTerminal.idl b/src/cascadia/TerminalSettingsModel/DefaultTerminal.idl index 9b3cc662d..94ceb48dd 100644 --- a/src/cascadia/TerminalSettingsModel/DefaultTerminal.idl +++ b/src/cascadia/TerminalSettingsModel/DefaultTerminal.idl @@ -9,8 +9,5 @@ namespace Microsoft.Terminal.Settings.Model String Author { get; }; String Version { get; }; String Icon { get; }; - - static DefaultTerminal Current; - static Windows.Foundation.Collections.IVectorView Available { get; }; } } From c727762602b8bd12e4a3a769053204d7e92b81c5 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Wed, 6 Oct 2021 19:02:53 +0200 Subject: [PATCH 08/71] Fix null pointer exceptions for default constructed CascadiaSettings instances (#11428) `CascadiaSettings` is default constructed when human readable error messages are returned. Even in such cases we need to ensure that all fields are properly initialized, as a caller might decide to call a `GlobalSettings` getter. Thus a crash occurred whenever a user was hot-reloading their settings file with invalid JSON as other code then tried to compare the `GlobalSettings()`. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed * Start Windows Terminal and ensure the settings load fine * Add `"commandline": 123` to any of the generated profiles in settings.json * The application doesn't crash and shows a warning message --- src/cascadia/TerminalSettingsModel/CascadiaSettings.h | 10 +++++----- .../CascadiaSettingsSerialization.cpp | 9 ++++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h index 176600c75..65856b5d5 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h @@ -154,13 +154,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation bool _hasInvalidColorScheme(const Model::Command& command) const; // user settings - winrt::com_ptr _globals; - winrt::com_ptr _baseLayerProfile; - winrt::Windows::Foundation::Collections::IObservableVector _allProfiles; - winrt::Windows::Foundation::Collections::IObservableVector _activeProfiles; + winrt::com_ptr _globals = winrt::make_self(); + winrt::com_ptr _baseLayerProfile = winrt::make_self(); + winrt::Windows::Foundation::Collections::IObservableVector _allProfiles = winrt::single_threaded_observable_vector(); + winrt::Windows::Foundation::Collections::IObservableVector _activeProfiles = winrt::single_threaded_observable_vector(); // load errors - winrt::Windows::Foundation::Collections::IVector _warnings; + winrt::Windows::Foundation::Collections::IVector _warnings = winrt::single_threaded_vector(); winrt::Windows::Foundation::IReference _loadError; winrt::hstring _deserializationErrorMessage; diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp index 6b92b99b7..224fe2851 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp @@ -742,7 +742,14 @@ CascadiaSettings::CascadiaSettings(const std::string_view& userJSON, const std:: { } -CascadiaSettings::CascadiaSettings(SettingsLoader&& loader) +CascadiaSettings::CascadiaSettings(SettingsLoader&& loader) : + // The CascadiaSettings class declaration initializes these fields by default, + // but we're going to set these fields in our constructor later on anyways. + _globals{}, + _baseLayerProfile{}, + _allProfiles{}, + _activeProfiles{}, + _warnings{} { std::vector allProfiles; std::vector activeProfiles; From bd8bfa13bb6ab6883536b0672abcf254aa666875 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 6 Oct 2021 16:11:09 -0500 Subject: [PATCH 09/71] Fix opening the debug tap (#11445) It's possible that we're about to be started, _before_ our paired connection is started. Both will get Start()'ed when their owning TermControl is finally laid out. However, if we're started first, then we'll immediately start printing to the other control as well, which might not have initialized yet. If we do that, we'll explode. Instead, wait here until the other connection is started too, before actually starting the connection to the client app. This will ensure both controls are initialized before the client app is. Fixes #11282 Tested: Opened about 100 debug taps. They all worked. :shipit: --- .../TerminalApp/DebugTapConnection.cpp | 19 ++++++++++++++++++- src/cascadia/TerminalApp/DebugTapConnection.h | 3 +++ src/cascadia/TerminalControl/ControlCore.cpp | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/cascadia/TerminalApp/DebugTapConnection.cpp b/src/cascadia/TerminalApp/DebugTapConnection.cpp index 54f327b3e..0d84d8f05 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.cpp +++ b/src/cascadia/TerminalApp/DebugTapConnection.cpp @@ -21,8 +21,22 @@ namespace winrt::Microsoft::TerminalApp::implementation } void Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) {} ~DebugInputTapConnection() = default; - void Start() + winrt::fire_and_forget Start() { + // GH#11282: It's possible that we're about to be started, _before_ + // our paired connection is started. Both will get Start()'ed when + // their owning TermControl is finally laid out. However, if we're + // started first, then we'll immediately start printing to the other + // control as well, which might not have initialized yet. If we do + // that, we'll explode. + // + // Instead, wait here until the other connection is started too, + // before actually starting the connection to the client app. This + // will ensure both controls are initialized before the client app + // is. + co_await winrt::resume_background(); + _pairedTap->_start.wait(); + _wrappedConnection.Start(); } void WriteInput(hstring const& data) @@ -59,6 +73,9 @@ namespace winrt::Microsoft::TerminalApp::implementation void DebugTapConnection::Start() { // presume the wrapped connection is started. + + // This is explained in the comment for GH#11282 above. + _start.count_down(); } void DebugTapConnection::WriteInput(hstring const& data) diff --git a/src/cascadia/TerminalApp/DebugTapConnection.h b/src/cascadia/TerminalApp/DebugTapConnection.h index c5156afc4..56d509fbf 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.h +++ b/src/cascadia/TerminalApp/DebugTapConnection.h @@ -5,6 +5,7 @@ #include #include "../../inc/cppwinrt_utils.h" +#include namespace winrt::Microsoft::TerminalApp::implementation { @@ -36,6 +37,8 @@ namespace winrt::Microsoft::TerminalApp::implementation winrt::weak_ref _wrappedConnection; winrt::weak_ref _inputSide; + til::latch _start{ 1 }; + friend class DebugInputTapConnection; }; } diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index efcce89c8..9c3af6bc3 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1025,7 +1025,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation TerminalConnection::ConnectionState ControlCore::ConnectionState() const { - return _connection.State(); + return _connection ? _connection.State() : TerminalConnection::ConnectionState::Closed; } hstring ControlCore::Title() From 694c6b263ff4a85a4f595cc3bd88d426bf822694 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 7 Oct 2021 06:39:20 -0500 Subject: [PATCH 10/71] When enabling opacity on win10, automatically enable acrylic (#11372) In #11180 we made `opacity` independent from `useAcrylic`. We also changed the mouse wheel behavior to only change opacity, and not mess with acrylic. However, on Windows 10, vintage opacity doesn't work at all. So there, we still need to manually enable acrylic when the user requests opacity. * [x] Closes #11285 SUI changes in action: ![auto-acrylic-win10](https://user-images.githubusercontent.com/18356694/136281935-db9a10f4-e0ad-4422-950b-0a01dc3e12c0.gif) --- src/cascadia/TerminalControl/ControlCore.cpp | 35 +++++++++++++++++++ src/cascadia/TerminalControl/ControlCore.h | 2 ++ .../TerminalSettingsEditor/Profiles.cpp | 16 +++++++++ .../TerminalSettingsEditor/Profiles.h | 14 ++++++++ .../UnitTests_Control/ControlCoreTests.cpp | 7 ++-- .../ControlInteractivityTests.cpp | 6 ++-- 6 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 9c3af6bc3..c287cdbd7 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -442,6 +442,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation _settings.Opacity(newOpacity); + // GH#11285 - If the user is on Windows 10, and they changed the + // transparency of the control s.t. it should be partially opaque, then + // opt them in to acrylic. It's the only way to have transparency on + // Windows 10. + // We'll also turn the acrylic back off when they're fully opaque, which + // is what the Terminal did prior to 1.12. + if (!IsVintageOpacityAvailable()) + { + _settings.UseAcrylic(newOpacity < 1.0); + } + auto eventArgs = winrt::make_self(newOpacity); _TransparencyChangedHandlers(*this, *eventArgs); } @@ -570,6 +581,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation _settings = settings; + // GH#11285 - If the user is on Windows 10, and they wanted opacity, but + // didn't explicitly request acrylic, then opt them in to acrylic. + // On Windows 11+, this isn't needed, because we can have vintage opacity. + if (!IsVintageOpacityAvailable() && _settings.Opacity() < 1.0 && !_settings.UseAcrylic()) + { + _settings.UseAcrylic(true); + } + // Initialize our font information. const auto fontFace = _settings.FontFace(); const short fontHeight = ::base::saturated_cast(_settings.FontSize()); @@ -1545,4 +1564,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation return hstring(ss.str()); } + + // Helper to check if we're on Windows 11 or not. This is used to check if + // we need to use acrylic to achieve transparency, because vintage opacity + // doesn't work in islands on win10. + // Remove when we can remove the rest of GH#11285 + bool ControlCore::IsVintageOpacityAvailable() noexcept + { + OSVERSIONINFOEXW osver{}; + osver.dwOSVersionInfoSize = sizeof(osver); + osver.dwBuildNumber = 22000; + + DWORDLONG dwlConditionMask = 0; + VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); + + return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE; + } } diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index a04032ef7..9b96f6c7e 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -149,6 +149,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation hstring ReadEntireBuffer() const; + static bool IsVintageOpacityAvailable() noexcept; + // -------------------------------- WinRT Events --------------------------------- // clang-format off WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs); diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.cpp b/src/cascadia/TerminalSettingsEditor/Profiles.cpp index 8e43f9b10..6c507ecf4 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.cpp +++ b/src/cascadia/TerminalSettingsEditor/Profiles.cpp @@ -47,6 +47,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation // NOTE: this is similar to what is done with BackgroundImagePath above _NotifyChanges(L"UseParentProcessDirectory", L"UseCustomStartingDirectory"); } + else if (viewModelProperty == L"UseAcrylic") + { + // GH#11372: If we're on Windows 10, and someone turns off + // acrylic, we're going to disable opacity for them. Opacity + // doesn't work without acrylic on Windows 10. + // + // BODGY: CascadiaSettings's function IsDefaultTerminalAvailable + // is basically a "are we on Windows 11" check, because defterm + // only works on Win11. So we'll use that. + // + // Remove when we can remove the rest of GH#11285 + if (!UseAcrylic() && !CascadiaSettings::IsDefaultTerminalAvailable()) + { + Opacity(1.0); + } + } }); // Do the same for the starting directory diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.h b/src/cascadia/TerminalSettingsEditor/Profiles.h index 74c31e49a..161f84e39 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.h +++ b/src/cascadia/TerminalSettingsEditor/Profiles.h @@ -23,6 +23,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void SetAcrylicOpacityPercentageValue(double value) { Opacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value)); + + // GH#11372: If we're on Windows 10, and someone wants opacity, then + // we'll turn acrylic on for them. Opacity doesn't work without + // acrylic on Windows 10. + // + // BODGY: CascadiaSettings's function IsDefaultTerminalAvailable + // is basically a "are we on Windows 11" check, because defterm + // only works on Win11. So we'll use that. + // + // Remove when we can remove the rest of GH#11285 + if (value < 100.0 && winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings::IsDefaultTerminalAvailable()) + { + UseAcrylic(true); + } }; void SetPadding(double value) diff --git a/src/cascadia/UnitTests_Control/ControlCoreTests.cpp b/src/cascadia/UnitTests_Control/ControlCoreTests.cpp index 9e4a19e7b..4c090b27e 100644 --- a/src/cascadia/UnitTests_Control/ControlCoreTests.cpp +++ b/src/cascadia/UnitTests_Control/ControlCoreTests.cpp @@ -139,8 +139,11 @@ namespace ControlUnitTests // GH#603: Adjusting opacity shouldn't change whether or not we // requested acrylic. - VERIFY_IS_TRUE(settings->UseAcrylic()); - VERIFY_IS_TRUE(core->_settings.UseAcrylic()); + + auto expectedUseAcrylic = winrt::Microsoft::Terminal::Control::implementation::ControlCore::IsVintageOpacityAvailable() ? true : + (expectedOpacity < 1.0 ? true : false); + VERIFY_ARE_EQUAL(expectedUseAcrylic, settings->UseAcrylic()); + VERIFY_ARE_EQUAL(expectedUseAcrylic, core->_settings.UseAcrylic()); }; core->TransparencyChanged(opacityCallback); diff --git a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp index db1e07435..51a2215e9 100644 --- a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp +++ b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp @@ -119,8 +119,10 @@ namespace ControlUnitTests VERIFY_ARE_EQUAL(expectedOpacity, settings->Opacity()); VERIFY_ARE_EQUAL(expectedOpacity, core->_settings.Opacity()); - VERIFY_ARE_EQUAL(useAcrylic, settings->UseAcrylic()); - VERIFY_ARE_EQUAL(useAcrylic, core->_settings.UseAcrylic()); + auto expectedUseAcrylic = winrt::Microsoft::Terminal::Control::implementation::ControlCore::IsVintageOpacityAvailable() ? useAcrylic : + (expectedOpacity < 1.0 ? true : false); + VERIFY_ARE_EQUAL(expectedUseAcrylic, settings->UseAcrylic()); + VERIFY_ARE_EQUAL(expectedUseAcrylic, core->_settings.UseAcrylic()); }; core->TransparencyChanged(opacityCallback); From 84e7ec4f96d1b83a177c5549b8f1e944f0fed20e Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Thu, 7 Oct 2021 18:30:34 +0200 Subject: [PATCH 11/71] Fix layering issues with CascadiaSettings::_createNewProfile (#11447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `CascadiaSettings::_createNewProfile` failed to call `_FinalizeInheritance`. This commits fixes the issue and adds a stern warning for future me. ## PR Checklist * [x] Closes #11392 * [x] I work here * [x] Tests added/passed ## Validation Steps Performed * Open settings UI * Modify font size in base layer * _Don't_ save * Duplicate any profile with default font size * Ensure the duplicated profile shows the modified base layer font size ✔️ --- .../LocalTests_SettingsModel/ProfileTests.cpp | 26 +++++++++++++------ .../CascadiaSettings.cpp | 8 ++++++ .../CascadiaSettingsSerialization.cpp | 1 + 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp b/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp index ee42b89a4..2c5138f6d 100644 --- a/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp +++ b/src/cascadia/LocalTests_SettingsModel/ProfileTests.cpp @@ -272,20 +272,30 @@ namespace SettingsModelLocalTests void ProfileTests::DuplicateProfileTest() { static constexpr std::string_view userProfiles{ R"({ - "profiles": [ - { - "name": "profile0", - "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", - "backgroundImage": "file:///some/path", - "hidden": false, - } - ] + "profiles": { + "defaults": { + "font": { + "size": 123 + } + }, + "list": [ + { + "name": "profile0", + "guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}", + "backgroundImage": "file:///some/path", + "hidden": false, + } + ] + } })" }; const auto settings = winrt::make_self(userProfiles); const auto profile = settings->AllProfiles().GetAt(0); const auto duplicatedProfile = settings->DuplicateProfile(profile); + // GH#11392: Ensure duplicated profiles properly inherit the base layer, even for nested objects. + VERIFY_ARE_EQUAL(123, duplicatedProfile.FontInfo().FontSize()); + duplicatedProfile.Guid(profile.Guid()); duplicatedProfile.Name(profile.Name()); diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index 4a9b274bf..ac7008416 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -18,6 +18,13 @@ using namespace winrt::Microsoft::Terminal::Control; using namespace winrt::Windows::Foundation::Collections; using namespace Microsoft::Console; +// Creating a child of a profile requires us to copy certain +// required attributes. This method handles those attributes. +// +// NOTE however that it doesn't call _FinalizeInheritance() for you! Don't forget that! +// +// At the time of writing only one caller needs to call _FinalizeInheritance(), +// which is why this unsafety wasn't further abstracted away. winrt::com_ptr Model::implementation::CreateChild(const winrt::com_ptr& parent) { auto profile = winrt::make_self(); @@ -371,6 +378,7 @@ winrt::com_ptr CascadiaSettings::_createNewProfile(const std::wstring_v LOG_IF_FAILED(CoCreateGuid(&guid)); auto profile = CreateChild(_baseLayerProfile); + profile->_FinalizeInheritance(); profile->Guid(guid); profile->Name(winrt::hstring{ name }); return profile; diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp index 224fe2851..c0e925c56 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp @@ -596,6 +596,7 @@ void SettingsLoader::_addParentProfile(const winrt::com_ptr Date: Thu, 7 Oct 2021 12:18:11 -0500 Subject: [PATCH 12/71] Make sure all the commandlines are fully qualified (#11437) This was originally in #11308. Thought we should check it in for 1.12 even though that won't merge this release. Should slightly mitigate the number of users that see this warning. --- src/cascadia/TerminalSettingsModel/Profile.h | 2 +- src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp | 6 +++++- src/cascadia/TerminalSettingsModel/userDefaults.json | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/cascadia/TerminalSettingsModel/Profile.h b/src/cascadia/TerminalSettingsModel/Profile.h index 9e54b0e7e..f69471332 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.h +++ b/src/cascadia/TerminalSettingsModel/Profile.h @@ -125,7 +125,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING); - INHERITABLE_SETTING(Model::Profile, hstring, Commandline, L"cmd.exe"); + INHERITABLE_SETTING(Model::Profile, hstring, Commandline, L"%SystemRoot%\\System32\\cmd.exe"); INHERITABLE_SETTING(Model::Profile, hstring, StartingDirectory); INHERITABLE_SETTING(Model::Profile, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale); diff --git a/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp index b0cfadfbd..8265b338a 100644 --- a/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp +++ b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp @@ -37,7 +37,11 @@ std::wstring_view WslDistroGenerator::GetNamespace() const noexcept static winrt::com_ptr makeProfile(const std::wstring& distName) { const auto WSLDistro{ CreateDynamicProfile(distName) }; - WSLDistro->Commandline(winrt::hstring{ L"wsl.exe -d " + distName }); + // GH#11096 - make sure the WSL path starts explicitly with + // C:\Windows\System32. Don't want someone path hijacking wsl.exe. + std::wstring command{}; + THROW_IF_FAILED(wil::GetSystemDirectoryW(command)); + WSLDistro->Commandline(winrt::hstring{ command + L"\\wsl.exe -d " + distName }); WSLDistro->DefaultAppearance().ColorSchemeName(L"Campbell"); WSLDistro->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY }); WSLDistro->Icon(L"ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png"); diff --git a/src/cascadia/TerminalSettingsModel/userDefaults.json b/src/cascadia/TerminalSettingsModel/userDefaults.json index 28ed3beef..59fa13a6d 100644 --- a/src/cascadia/TerminalSettingsModel/userDefaults.json +++ b/src/cascadia/TerminalSettingsModel/userDefaults.json @@ -10,13 +10,13 @@ { "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", "name": "Windows PowerShell", - "commandline": "powershell.exe", + "commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "hidden": false }, { // "name" is filled in by CascadiaSettings as a localized string. "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", - "commandline": "cmd.exe", + "commandline": "%SystemRoot%\\System32\\cmd.exe", "hidden": false } ] From 2b1468eaa2ad3f5310c7a8b29bf4e1e52bb1a188 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Thu, 7 Oct 2021 19:44:03 +0200 Subject: [PATCH 13/71] Add a information popup about default terminals (#11397) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a simple information popup about default terminals, guiding first-time Windows 11 users into changing the default terminal. ## Validation Steps Performed * Info bar pops up on Windows 11 ✔️ * Info bar can be dismissed persistently ✔️ --- .../Resources/en-US/Resources.resw | 3 + src/cascadia/TerminalApp/TerminalPage.cpp | 58 +++++++++++++++++-- src/cascadia/TerminalApp/TerminalPage.h | 2 + src/cascadia/TerminalApp/TerminalPage.xaml | 13 +++++ .../ApplicationState.idl | 3 +- .../CascadiaSettings.cpp | 11 ++++ .../TerminalSettingsModel/CascadiaSettings.h | 1 + .../CascadiaSettings.idl | 1 + .../TerminalSettingsModel/DefaultTerminal.cpp | 10 ++++ .../TerminalSettingsModel/DefaultTerminal.h | 1 + .../TerminalSettingsSerializationHelpers.h | 3 +- 11 files changed, 99 insertions(+), 7 deletions(-) diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 55e51abbb..c9f84a239 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -718,6 +718,9 @@ Termination behavior can be configured in advanced profile settings. + + Windows Terminal can be set as the default terminal application in your settings. + Don't show again diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 25140362d..8501f117d 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -287,6 +287,8 @@ namespace winrt::TerminalApp::implementation _defaultPointerCursor = CoreWindow::GetForCurrentThread().PointerCursor(); } CATCH_LOG(); + + ShowSetAsDefaultInfoBar(); } // Method Description; @@ -2893,6 +2895,29 @@ namespace winrt::TerminalApp::implementation } } + // Method Description: + // - Displays a info popup guiding the user into setting their default terminal. + void TerminalPage::ShowSetAsDefaultInfoBar() const + { + if (!CascadiaSettings::IsDefaultTerminalAvailable() || _IsMessageDismissed(InfoBarMessage::SetAsDefault)) + { + return; + } + + // If the user has already configured any terminal for hand-off we + // shouldn't inform them again about the possibility to do so. + if (CascadiaSettings::IsDefaultTerminalSet()) + { + _DismissMessage(InfoBarMessage::SetAsDefault); + return; + } + + if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as()) + { + infoBar.IsOpen(true); + } + } + // Function Description: // - Helper function to get the OS-localized name for the "Touch Keyboard // and Handwriting Panel Service". If we can't open up the service for any @@ -3313,6 +3338,22 @@ namespace winrt::TerminalApp::implementation } } + // Method Description: + // - Persists the user's choice not to show the information bar warning about "Windows Terminal can be set as your default terminal application" + // Then hides this information buffer. + // Arguments: + // - + // Return Value: + // - + void TerminalPage::_SetAsDefaultDismissHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/) const + { + _DismissMessage(InfoBarMessage::SetAsDefault); + if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as()) + { + infoBar.IsOpen(false); + } + } + // Method Description: // - Checks whether information bar message was dismissed earlier (in the application state) // Arguments: @@ -3342,13 +3383,20 @@ namespace winrt::TerminalApp::implementation // - void TerminalPage::_DismissMessage(const InfoBarMessage& message) { - auto dismissedMessages = ApplicationState::SharedInstance().DismissedMessages(); - if (!dismissedMessages) + const auto applicationState = ApplicationState::SharedInstance(); + std::vector messages; + + if (const auto values = applicationState.DismissedMessages()) { - dismissedMessages = winrt::single_threaded_vector(); + messages.resize(values.Size()); + values.GetMany(0, messages); } - dismissedMessages.Append(message); - ApplicationState::SharedInstance().DismissedMessages(dismissedMessages); + if (std::none_of(messages.begin(), messages.end(), [&](const auto& m) { return m == message; })) + { + messages.emplace_back(message); + } + + applicationState.DismissedMessages(std::move(messages)); } } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 26332453a..6fdc88d15 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -95,6 +95,7 @@ namespace winrt::TerminalApp::implementation winrt::TerminalApp::TaskbarState TaskbarState() const; void ShowKeyboardServiceWarning() const; + void ShowSetAsDefaultInfoBar() const; winrt::hstring KeyboardServiceDisabledText(); winrt::fire_and_forget IdentifyWindow(); @@ -403,6 +404,7 @@ namespace winrt::TerminalApp::implementation winrt::fire_and_forget _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const; void _CloseOnExitInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const; void _KeyboardServiceWarningInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const; + void _SetAsDefaultDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const; static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message); static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message); diff --git a/src/cascadia/TerminalApp/TerminalPage.xaml b/src/cascadia/TerminalApp/TerminalPage.xaml index b6a4676dd..f5e5b7df4 100644 --- a/src/cascadia/TerminalApp/TerminalPage.xaml +++ b/src/cascadia/TerminalApp/TerminalPage.xaml @@ -141,6 +141,19 @@ Click="_CloseOnExitInfoDismissHandler" /> + + + +