Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/honk

This commit is contained in:
Mike Griese 2021-11-16 09:18:59 -06:00
commit 2eda14cc1b
170 changed files with 5689 additions and 1809 deletions

View file

@ -10,14 +10,21 @@ body:
- type: input - type: input
attributes: attributes:
label: Windows Terminal version (or Windows build number) label: Windows Terminal version
placeholder: "10.0.19042.0, 1.7.3651.0" placeholder: "1.7.3651.0"
description: | description: |
If you are reporting an issue in Windows Terminal, you can find the version in the about dialog. You can find the version in the about dialog, or by running `wt -v` at the commandline.
If you are reporting an issue with the Windows Console, please run `ver` or `[Environment]::OSVersion`.
validations: validations:
required: true required: false
- type: input
attributes:
label: Windows build number
placeholder: "10.0.19042.0"
description: |
Please run `ver` or `[Environment]::OSVersion`.
validations:
required: false
- type: textarea - type: textarea
attributes: attributes:

View file

@ -1,12 +1,14 @@
admins
apc apc
Apc
bsd
calt calt
ccmp ccmp
changelog changelog
cybersecurity
Apc
clickable clickable
clig clig
copyable copyable
cybersecurity
dalet dalet
dcs dcs
Dcs Dcs
@ -34,16 +36,17 @@ It'd
kje kje
liga liga
lje lje
locl
lorem
Llast Llast
Lmid Lmid
locl
lorem
Lorigin Lorigin
maxed maxed
mkmk mkmk
mnt
mru mru
noreply
nje nje
noreply
ogonek ogonek
ok'd ok'd
overlined overlined

View file

@ -1,5 +1,7 @@
ACCEPTFILES ACCEPTFILES
ACCESSDENIED ACCESSDENIED
acl
aclapi
alignas alignas
alignof alignof
APPLYTOSUBMENUS APPLYTOSUBMENUS
@ -9,6 +11,7 @@ BUILDBRANCH
BUILDMSG BUILDMSG
BUILDNUMBER BUILDNUMBER
BYPOSITION BYPOSITION
BYCOMMAND
charconv charconv
CLASSNOTAVAILABLE CLASSNOTAVAILABLE
cmdletbinding cmdletbinding
@ -16,9 +19,11 @@ COLORPROPERTY
colspan colspan
COMDLG COMDLG
comparand comparand
commandlinetoargv
cstdint cstdint
CXICON CXICON
CYICON CYICON
Dacl
dataobject dataobject
dcomp dcomp
DERR DERR
@ -85,6 +90,7 @@ LSHIFT
MENUCOMMAND MENUCOMMAND
MENUDATA MENUDATA
MENUINFO MENUINFO
MENUITEMINFOW
memicmp memicmp
mptt mptt
mov mov
@ -114,15 +120,19 @@ OSVERSIONINFOEXW
otms otms
OUTLINETEXTMETRICW OUTLINETEXTMETRICW
overridable overridable
PACL
PAGESCROLL PAGESCROLL
PEXPLICIT
PICKFOLDERS PICKFOLDERS
pmr pmr
ptstr
rcx rcx
REGCLS REGCLS
RETURNCMD RETURNCMD
rfind rfind
roundf roundf
RSHIFT RSHIFT
SACL
schandle schandle
semver semver
serializer serializer
@ -159,6 +169,7 @@ toupper
TTask TTask
TVal TVal
UChar UChar
ULARGE
UPDATEINIFILE UPDATEINIFILE
userenv userenv
wcsstr wcsstr

View file

@ -9,6 +9,7 @@ Diviness
dsafa dsafa
duhowett duhowett
ekg ekg
eryksun
ethanschoonover ethanschoonover
Firefox Firefox
Gatta Gatta

View file

@ -61,6 +61,7 @@ SUMS$
^src/host/runft\.bat$ ^src/host/runft\.bat$
^src/host/runut\.bat$ ^src/host/runut\.bat$
^src/interactivity/onecore/BgfxEngine\. ^src/interactivity/onecore/BgfxEngine\.
^src/renderer/atlas/
^src/renderer/wddmcon/WddmConRenderer\. ^src/renderer/wddmcon/WddmConRenderer\.
^src/terminal/adapter/ut_adapter/run\.bat$ ^src/terminal/adapter/ut_adapter/run\.bat$
^src/terminal/parser/delfuzzpayload\.bat$ ^src/terminal/parser/delfuzzpayload\.bat$

View file

@ -400,6 +400,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsTerminal.UIA.Tests",
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api-ms-win-core-synch-l1-2-0", "src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj", "{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api-ms-win-core-synch-l1-2-0", "src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj", "{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererAtlas", "src\renderer\atlas\atlas.vcxproj", "{8222900C-8B6C-452A-91AC-BE95DB04B95F}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
AuditMode|Any CPU = AuditMode|Any CPU AuditMode|Any CPU = AuditMode|Any CPU
@ -3339,6 +3341,46 @@ Global
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x64.Build.0 = Release|x64 {9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x64.Build.0 = Release|x64
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.ActiveCfg = Release|Win32 {9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.ActiveCfg = Release|Win32
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.Build.0 = Release|Win32 {9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.Build.0 = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x64.ActiveCfg = AuditMode|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x64.Build.0 = AuditMode|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x86.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x86.Build.0 = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|Any CPU.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.Build.0 = Debug|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.ActiveCfg = Debug|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.Build.0 = Debug|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x86.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x86.Build.0 = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x64.Build.0 = Fuzzing|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x86.Build.0 = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|Any CPU.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.ActiveCfg = Release|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.Build.0 = Release|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.ActiveCfg = Release|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.Build.0 = Release|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x86.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -3438,6 +3480,7 @@ Global
{C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} {C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{F19DACD5-0C6E-40DC-B6E4-767A3200542C} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} {F19DACD5-0C6E-40DC-B6E4-767A3200542C} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5} = {89CDCC5C-9F53-4054-97A4-639D99F169CD} {9CF74355-F018-4C19-81AD-9DC6B7F2C6F5} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
{8222900C-8B6C-452A-91AC-BE95DB04B95F} = {05500DEF-2294-41E3-AF9A-24E580B82836}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271} SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}

View file

@ -214,7 +214,7 @@ resources useful and interesting:
* Windows Terminal Launch: [Build 2019 * Windows Terminal Launch: [Build 2019
Session](https://www.youtube.com/watch?v=KMudkRcwjCw) Session](https://www.youtube.com/watch?v=KMudkRcwjCw)
* Run As Radio: [Show 645 - Windows Terminal with Richard * Run As Radio: [Show 645 - Windows Terminal with Richard
Turner](http://www.runasradio.com/Shows/Show/645) Turner](https://www.runasradio.com/Shows/Show/645)
* Azure Devops Podcast: [Episode 54 - Kayla Cinnamon and Rich Turner on DevOps * Azure Devops Podcast: [Episode 54 - Kayla Cinnamon and Rich Turner on DevOps
on the Windows on the Windows
Terminal](http://azuredevopspodcast.clear-measure.com/kayla-cinnamon-and-rich-turner-on-devops-on-the-windows-terminal-team-episode-54) Terminal](http://azuredevopspodcast.clear-measure.com/kayla-cinnamon-and-rich-turner-on-devops-on-the-windows-terminal-team-episode-54)

View file

@ -1478,6 +1478,11 @@
"description": "When set to true, trailing white-spaces will be removed from text in rectangular (block) selection while copied to your clipboard. When set to false, the white-spaces will be preserved.", "description": "When set to true, trailing white-spaces will be removed from text in rectangular (block) selection while copied to your clipboard. When set to false, the white-spaces will be preserved.",
"type": "boolean" "type": "boolean"
}, },
"trimPaste": {
"default": true,
"description": "When enabled, the Terminal will automatically trim trailing whitespace characters when pasting text",
"type": "boolean"
},
"experimental.detectURLs": { "experimental.detectURLs": {
"default": true, "default": true,
"description": "When set to true, URLs will be detected by the Terminal. This will cause URLs to underline on hover and be clickable by pressing Ctrl.", "description": "When set to true, URLs will be detected by the Terminal. This will cause URLs to underline on hover and be clickable by pressing Ctrl.",

View file

@ -268,7 +268,7 @@ Today, if the deserialization of `CascadiaSettings` encounters any errors, an ex
To get around this issue, when `CascadiaSettings` encounters a serialization error, it must internally record To get around this issue, when `CascadiaSettings` encounters a serialization error, it must internally record
any pertinent information for that error, and return the simple `CascadiaSettings` as if nothing happened. any pertinent information for that error, and return the simple `CascadiaSettings` as if nothing happened.
The consumer must then call `CascadiaSettings::GetErrors()` and `CascadiaSettings::GetWarnings()` to properly The consumer must then call `CascadiaSettings::GetErrors()` and `CascadiaSettings::GetWarnings()` to properly
understand whether an error ocurred and how to present that to the user. understand whether an error occurred and how to present that to the user.
#### TerminalApp: Loading and Reloading Changes #### TerminalApp: Loading and Reloading Changes

View file

@ -12,8 +12,30 @@ static_assert(alignof(TextAttribute) == 2);
// Ensure that we can memcpy() and memmove() the struct for performance. // Ensure that we can memcpy() and memmove() the struct for performance.
static_assert(std::is_trivially_copyable_v<TextAttribute>); static_assert(std::is_trivially_copyable_v<TextAttribute>);
BYTE TextAttribute::s_legacyDefaultForeground = 7; namespace
BYTE TextAttribute::s_legacyDefaultBackground = 0; {
constexpr std::array<TextColor, 16> s_initLegacyColorMap(const BYTE defaultIndex)
{
std::array<TextColor, 16> legacyColorMap;
for (auto i = 0u; i < legacyColorMap.size(); i++)
{
const auto legacyIndex = TextColor::TransposeLegacyIndex(i);
gsl::at(legacyColorMap, i) = i == defaultIndex ? TextColor{} : TextColor{ legacyIndex, true };
}
return legacyColorMap;
}
BYTE s_legacyDefaultForeground = 7;
BYTE s_legacyDefaultBackground = 0;
BYTE s_ansiDefaultForeground = 7;
BYTE s_ansiDefaultBackground = 0;
}
// These maps allow for an efficient conversion from a legacy attribute index
// to a TextColor with the corresponding ANSI index, also taking into account
// the legacy index values that need to be converted to a default TextColor.
std::array<TextColor, 16> TextAttribute::s_legacyForegroundColorMap = s_initLegacyColorMap(7);
std::array<TextColor, 16> TextAttribute::s_legacyBackgroundColorMap = s_initLegacyColorMap(0);
// Routine Description: // Routine Description:
// - Sets the legacy attributes which map to and from the default colors. // - Sets the legacy attributes which map to and from the default colors.
@ -23,8 +45,22 @@ BYTE TextAttribute::s_legacyDefaultBackground = 0;
// - None // - None
void TextAttribute::SetLegacyDefaultAttributes(const WORD defaultAttributes) noexcept void TextAttribute::SetLegacyDefaultAttributes(const WORD defaultAttributes) noexcept
{ {
// First we reset the current default color map entries to what they should
// be for a regular translation from a legacy index to an ANSI TextColor.
gsl::at(s_legacyForegroundColorMap, s_legacyDefaultForeground) = TextColor{ s_ansiDefaultForeground, true };
gsl::at(s_legacyBackgroundColorMap, s_legacyDefaultBackground) = TextColor{ s_ansiDefaultBackground, true };
// Then we save the new default attribute values and their corresponding
// ANSI translations. We use the latter values to more efficiently handle
// the "VT Quirk" conversion below.
s_legacyDefaultForeground = defaultAttributes & FG_ATTRS; s_legacyDefaultForeground = defaultAttributes & FG_ATTRS;
s_legacyDefaultBackground = (defaultAttributes & BG_ATTRS) >> 4; s_legacyDefaultBackground = (defaultAttributes & BG_ATTRS) >> 4;
s_ansiDefaultForeground = TextColor::TransposeLegacyIndex(s_legacyDefaultForeground);
s_ansiDefaultBackground = TextColor::TransposeLegacyIndex(s_legacyDefaultBackground);
// Finally we set the new default color map entries.
gsl::at(s_legacyForegroundColorMap, s_legacyDefaultForeground) = TextColor{};
gsl::at(s_legacyBackgroundColorMap, s_legacyDefaultBackground) = TextColor{};
} }
// Routine Description: // Routine Description:
@ -55,13 +91,13 @@ TextAttribute TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(const Te
const auto bg{ attribute.GetBackground() }; const auto bg{ attribute.GetBackground() };
auto copy{ attribute }; auto copy{ attribute };
if (fg.IsIndex16() && if (fg.IsIndex16() &&
attribute.IsBold() == WI_IsFlagSet(s_legacyDefaultForeground, FOREGROUND_INTENSITY) && attribute.IsBold() == WI_IsFlagSet(s_ansiDefaultForeground, FOREGROUND_INTENSITY) &&
fg.GetIndex() == (s_legacyDefaultForeground & ~FOREGROUND_INTENSITY)) fg.GetIndex() == (s_ansiDefaultForeground & ~FOREGROUND_INTENSITY))
{ {
// We don't want to turn 1;37m into 39m (or even 1;39m), as this was meant to mimic a legacy color. // We don't want to turn 1;37m into 39m (or even 1;39m), as this was meant to mimic a legacy color.
copy.SetDefaultForeground(); copy.SetDefaultForeground();
} }
if (bg.IsIndex16() && bg.GetIndex() == s_legacyDefaultBackground) if (bg.IsIndex16() && bg.GetIndex() == s_ansiDefaultBackground)
{ {
copy.SetDefaultBackground(); copy.SetDefaultBackground();
} }

View file

@ -41,8 +41,8 @@ public:
explicit constexpr TextAttribute(const WORD wLegacyAttr) noexcept : explicit constexpr TextAttribute(const WORD wLegacyAttr) noexcept :
_wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) }, _wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) },
_foreground{ s_LegacyIndexOrDefault(wLegacyAttr & FG_ATTRS, s_legacyDefaultForeground) }, _foreground{ gsl::at(s_legacyForegroundColorMap, wLegacyAttr & FG_ATTRS) },
_background{ s_LegacyIndexOrDefault((wLegacyAttr & BG_ATTRS) >> 4, s_legacyDefaultBackground) }, _background{ gsl::at(s_legacyBackgroundColorMap, (wLegacyAttr & BG_ATTRS) >> 4) },
_extendedAttrs{ ExtendedAttributes::Normal }, _extendedAttrs{ ExtendedAttributes::Normal },
_hyperlinkId{ 0 } _hyperlinkId{ 0 }
{ {
@ -167,13 +167,8 @@ public:
} }
private: private:
static constexpr TextColor s_LegacyIndexOrDefault(const BYTE requestedIndex, const BYTE defaultIndex) static std::array<TextColor, 16> s_legacyForegroundColorMap;
{ static std::array<TextColor, 16> s_legacyBackgroundColorMap;
return requestedIndex == defaultIndex ? TextColor{} : TextColor{ requestedIndex, true };
}
static BYTE s_legacyDefaultForeground;
static BYTE s_legacyDefaultBackground;
uint16_t _wAttrLegacy; // sizeof: 2, alignof: 2 uint16_t _wAttrLegacy; // sizeof: 2, alignof: 2
uint16_t _hyperlinkId; // sizeof: 2, alignof: 2 uint16_t _hyperlinkId; // sizeof: 2, alignof: 2

View file

@ -32,7 +32,7 @@ constexpr std::array<BYTE, 256> CompressedRgbToIndex16 = {
// A table mapping indexed colors from the 256-color palette, // A table mapping indexed colors from the 256-color palette,
// down to one of the 16 colors in the legacy palette. // down to one of the 16 colors in the legacy palette.
constexpr std::array<BYTE, 256> Index256ToIndex16 = { constexpr std::array<BYTE, 256> Index256ToIndex16 = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15,
0, 1, 1, 1, 9, 9, 2, 1, 1, 1, 1, 1, 2, 2, 3, 3, 0, 1, 1, 1, 9, 9, 2, 1, 1, 1, 1, 1, 2, 2, 3, 3,
3, 3, 2, 2, 11, 11, 3, 3, 10, 10, 11, 11, 11, 11, 10, 10, 3, 3, 2, 2, 11, 11, 3, 3, 10, 10, 11, 11, 11, 11, 10, 10,
10, 10, 11, 11, 5, 5, 5, 5, 1, 1, 8, 8, 1, 1, 9, 9, 10, 10, 11, 11, 5, 5, 5, 5, 1, 1, 8, 8, 1, 1, 9, 9,
@ -252,11 +252,7 @@ BYTE TextColor::GetLegacyIndex(const BYTE defaultIndex) const noexcept
{ {
return defaultIndex; return defaultIndex;
} }
else if (IsIndex16()) else if (IsIndex16() || IsIndex256())
{
return GetIndex();
}
else if (IsIndex256())
{ {
return til::at(Index256ToIndex16, GetIndex()); return til::at(Index256ToIndex16, GetIndex());
} }

View file

@ -48,6 +48,23 @@ enum class ColorType : BYTE
struct TextColor struct TextColor
{ {
public: public:
static constexpr BYTE DARK_BLACK = 0;
static constexpr BYTE DARK_RED = 1;
static constexpr BYTE DARK_GREEN = 2;
static constexpr BYTE DARK_YELLOW = 3;
static constexpr BYTE DARK_BLUE = 4;
static constexpr BYTE DARK_MAGENTA = 5;
static constexpr BYTE DARK_CYAN = 6;
static constexpr BYTE DARK_WHITE = 7;
static constexpr BYTE BRIGHT_BLACK = 8;
static constexpr BYTE BRIGHT_RED = 9;
static constexpr BYTE BRIGHT_GREEN = 10;
static constexpr BYTE BRIGHT_YELLOW = 11;
static constexpr BYTE BRIGHT_BLUE = 12;
static constexpr BYTE BRIGHT_MAGENTA = 13;
static constexpr BYTE BRIGHT_CYAN = 14;
static constexpr BYTE BRIGHT_WHITE = 15;
constexpr TextColor() noexcept : constexpr TextColor() noexcept :
_meta{ ColorType::IsDefault }, _meta{ ColorType::IsDefault },
_red{ 0 }, _red{ 0 },
@ -96,6 +113,16 @@ public:
COLORREF GetRGB() const noexcept; COLORREF GetRGB() const noexcept;
static constexpr BYTE TransposeLegacyIndex(const size_t index)
{
// When converting a 16-color index in the legacy Windows order to or
// from an ANSI-compatible order, we need to swap the bits in positions
// 0 and 2. We do this by XORing the index with 00000101, but only if
// one (but not both) of those bit positions is set.
const auto oneBitSet = (index ^ (index >> 2)) & 1;
return gsl::narrow_cast<BYTE>(index ^ oneBitSet ^ (oneBitSet << 2));
}
private: private:
union union
{ {

View file

@ -237,7 +237,7 @@ void TextAttributeTests::TestRoundtripDefaultColors()
Log::Comment(L"Foreground legacy default index should map to default text color."); Log::Comment(L"Foreground legacy default index should map to default text color.");
legacyAttribute = fgLegacyDefault | BACKGROUND_GREEN; legacyAttribute = fgLegacyDefault | BACKGROUND_GREEN;
textAttribute.SetDefaultForeground(); textAttribute.SetDefaultForeground();
textAttribute.SetIndexedBackground256(BACKGROUND_GREEN >> 4); textAttribute.SetIndexedBackground256(TextColor::DARK_GREEN);
VERIFY_ARE_EQUAL(textAttribute, TextAttribute{ legacyAttribute }); VERIFY_ARE_EQUAL(textAttribute, TextAttribute{ legacyAttribute });
Log::Comment(L"Default foreground text color should map back to legacy default index."); Log::Comment(L"Default foreground text color should map back to legacy default index.");
@ -245,7 +245,7 @@ void TextAttributeTests::TestRoundtripDefaultColors()
Log::Comment(L"Background legacy default index should map to default text color."); Log::Comment(L"Background legacy default index should map to default text color.");
legacyAttribute = FOREGROUND_GREEN | bgLegacyDefault; legacyAttribute = FOREGROUND_GREEN | bgLegacyDefault;
textAttribute.SetIndexedForeground256(FOREGROUND_GREEN); textAttribute.SetIndexedForeground256(TextColor::DARK_GREEN);
textAttribute.SetDefaultBackground(); textAttribute.SetDefaultBackground();
VERIFY_ARE_EQUAL(textAttribute, TextAttribute{ legacyAttribute }); VERIFY_ARE_EQUAL(textAttribute, TextAttribute{ legacyAttribute });
@ -288,7 +288,7 @@ void TextAttributeTests::TestBoldAsBright()
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true)); VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false)); VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
attr.SetIndexedForeground(0); attr.SetIndexedForeground(TextColor::DARK_BLACK);
VERIFY_IS_TRUE(attr.IsBold()); VERIFY_IS_TRUE(attr.IsBold());
Log::Comment(L"Foreground should be bright black when bold is bright is enabled"); Log::Comment(L"Foreground should be bright black when bold is bright is enabled");
@ -297,7 +297,7 @@ void TextAttributeTests::TestBoldAsBright()
Log::Comment(L"Foreground should be dark black when bold is bright is disabled"); Log::Comment(L"Foreground should be dark black when bold is bright is disabled");
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false)); VERIFY_ARE_EQUAL(std::make_pair(darkBlack, _defaultBg), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));
attr.SetIndexedBackground(2); attr.SetIndexedBackground(TextColor::DARK_GREEN);
VERIFY_IS_TRUE(attr.IsBold()); VERIFY_IS_TRUE(attr.IsBold());
Log::Comment(L"background should be unaffected by 'bold is bright'"); Log::Comment(L"background should be unaffected by 'bold is bright'");
@ -312,7 +312,7 @@ void TextAttributeTests::TestBoldAsBright()
Log::Comment(L"When set to a bright color, and bold, 'bold is bright' changes nothing"); Log::Comment(L"When set to a bright color, and bold, 'bold is bright' changes nothing");
attr.SetBold(true); attr.SetBold(true);
attr.SetIndexedForeground(8); attr.SetIndexedForeground(TextColor::BRIGHT_BLACK);
VERIFY_IS_TRUE(attr.IsBold()); VERIFY_IS_TRUE(attr.IsBold());
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true)); VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, true));
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false)); VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), attr.CalculateRgbColors(_colorTable, _defaultFg, _defaultBg, false, false, false));

View file

@ -80,7 +80,7 @@ namespace SettingsModelLocalTests
std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable; std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
const auto campbellSpan = gsl::make_span(expectedCampbellTable); const auto campbellSpan = gsl::make_span(expectedCampbellTable);
Utils::InitializeCampbellColorTable(campbellSpan); Utils::InitializeColorTable(campbellSpan);
Utils::SetColorTableAlpha(campbellSpan, 0); Utils::SetColorTableAlpha(campbellSpan, 0);
for (size_t i = 0; i < expectedCampbellTable.size(); i++) for (size_t i = 0; i < expectedCampbellTable.size(); i++)

View file

@ -508,7 +508,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(L"Duplicate the first pane")); Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
result = RunOnUIThread([&page]() { result = RunOnUIThread([&page]() {
page->_SplitPane(SplitDirection::Automatic, SplitType::Duplicate, 0.5f, nullptr); page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
VERIFY_ARE_EQUAL(1u, page->_tabs.Size()); VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0)); auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
@ -526,7 +526,7 @@ namespace TerminalAppLocalTests
Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash")); Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash"));
result = RunOnUIThread([&page]() { result = RunOnUIThread([&page]() {
page->_SplitPane(SplitDirection::Automatic, SplitType::Duplicate, 0.5f, nullptr); page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
VERIFY_ARE_EQUAL(1u, page->_tabs.Size()); VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0)); auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
@ -844,7 +844,7 @@ namespace TerminalAppLocalTests
// | 1 | 2 | // | 1 | 2 |
// | | | // | | |
// ------------------- // -------------------
page->_SplitPane(SplitDirection::Right, SplitType::Duplicate, 0.5f, nullptr); page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, true, nullptr));
secondId = tab->_activePane->Id().value(); secondId = tab->_activePane->Id().value();
}); });
Sleep(250); Sleep(250);
@ -862,7 +862,7 @@ namespace TerminalAppLocalTests
// | 3 | | // | 3 | |
// | | | // | | |
// ------------------- // -------------------
page->_SplitPane(SplitDirection::Down, SplitType::Duplicate, 0.5f, nullptr); page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0)); auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
// Split again to make the 3rd tab // Split again to make the 3rd tab
thirdId = tab->_activePane->Id().value(); thirdId = tab->_activePane->Id().value();
@ -882,7 +882,7 @@ namespace TerminalAppLocalTests
// | 3 | 4 | // | 3 | 4 |
// | | | // | | |
// ------------------- // -------------------
page->_SplitPane(SplitDirection::Down, SplitType::Duplicate, 0.5f, nullptr); page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0)); auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
fourthId = tab->_activePane->Id().value(); fourthId = tab->_activePane->Id().value();
}); });

View file

@ -29,6 +29,9 @@
<ProjectReference Include="$(SolutionDir)src\types\lib\types.vcxproj"> <ProjectReference Include="$(SolutionDir)src\types\lib\types.vcxproj">
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project> <Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="$(SolutionDir)src\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)src\renderer\base\lib\base.vcxproj"> <ProjectReference Include="$(SolutionDir)src\renderer\base\lib\base.vcxproj">
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project> <Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
</ProjectReference> </ProjectReference>

View file

@ -174,10 +174,9 @@ namespace winrt::TerminalApp::implementation
else if (const auto& realArgs = args.ActionArgs().try_as<SplitPaneArgs>()) else if (const auto& realArgs = args.ActionArgs().try_as<SplitPaneArgs>())
{ {
_SplitPane(realArgs.SplitDirection(), _SplitPane(realArgs.SplitDirection(),
realArgs.SplitMode(),
// This is safe, we're already filtering so the value is (0, 1) // This is safe, we're already filtering so the value is (0, 1)
::base::saturated_cast<float>(realArgs.SplitSize()), ::base::saturated_cast<float>(realArgs.SplitSize()),
realArgs.TerminalArgs()); _MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
args.Handled(true); args.Handled(true);
} }
} }

View file

@ -12,6 +12,8 @@
#include <WtExeUtils.h> #include <WtExeUtils.h>
#include <wil/token_helpers.h > #include <wil/token_helpers.h >
#include "../../types/inc/utils.hpp"
using namespace winrt::Windows::ApplicationModel; using namespace winrt::Windows::ApplicationModel;
using namespace winrt::Windows::ApplicationModel::DataTransfer; using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::UI::Xaml; using namespace winrt::Windows::UI::Xaml;
@ -131,38 +133,6 @@ static Documents::Run _BuildErrorRun(const winrt::hstring& text, const ResourceD
return textRun; return textRun;
} }
// Method Description:
// - Returns whether the user is either a member of the Administrators group or
// is currently elevated.
// - This will return **FALSE** if the user has UAC disabled entirely, because
// there's no separation of power between the user and an admin in that case.
// Return Value:
// - true if the user is an administrator
static bool _isUserAdmin() noexcept
try
{
wil::unique_handle processToken{ GetCurrentProcessToken() };
const auto elevationType = wil::get_token_information<TOKEN_ELEVATION_TYPE>(processToken.get());
const auto elevationState = wil::get_token_information<TOKEN_ELEVATION>(processToken.get());
if (elevationType == TokenElevationTypeDefault && elevationState.TokenIsElevated)
{
// In this case, the user has UAC entirely disabled. This is sort of
// weird, we treat this like the user isn't an admin at all. There's no
// separation of powers, so the things we normally want to gate on
// "having special powers" doesn't apply.
//
// See GH#7754, GH#11096
return false;
}
return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return false;
}
namespace winrt::TerminalApp::implementation namespace winrt::TerminalApp::implementation
{ {
// Function Description: // Function Description:
@ -214,7 +184,7 @@ namespace winrt::TerminalApp::implementation
// The TerminalPage has to be constructed during our construction, to // The TerminalPage has to be constructed during our construction, to
// make sure that there's a terminal page for callers of // make sure that there's a terminal page for callers of
// SetTitleBarContent // SetTitleBarContent
_isElevated = _isUserAdmin(); _isElevated = ::Microsoft::Console::Utils::IsElevated();
_root = winrt::make_self<TerminalPage>(); _root = winrt::make_self<TerminalPage>();
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() { _reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
@ -334,6 +304,9 @@ namespace winrt::TerminalApp::implementation
_RefreshThemeRoutine(); _RefreshThemeRoutine();
_ApplyStartupTaskStateChange(); _ApplyStartupTaskStateChange();
auto args = winrt::make_self<SystemMenuChangeArgs>(RS_(L"SettingsMenuItem"), SystemMenuChangeAction::Add, SystemMenuItemHandler(this, &AppLogic::_OpenSettingsUI));
_SystemMenuChangeRequestedHandlers(*this, *args);
TraceLoggingWrite( TraceLoggingWrite(
g_hTerminalAppProvider, g_hTerminalAppProvider,
"AppCreated", "AppCreated",
@ -907,8 +880,6 @@ namespace winrt::TerminalApp::implementation
void AppLogic::_RegisterSettingsChange() void AppLogic::_RegisterSettingsChange()
{ {
const std::filesystem::path settingsPath{ std::wstring_view{ CascadiaSettings::SettingsPath() } }; const std::filesystem::path settingsPath{ std::wstring_view{ CascadiaSettings::SettingsPath() } };
const std::filesystem::path statePath{ std::wstring_view{ ApplicationState::SharedInstance().FilePath() } };
_reader.create( _reader.create(
settingsPath.parent_path().c_str(), settingsPath.parent_path().c_str(),
false, false,
@ -917,14 +888,29 @@ namespace winrt::TerminalApp::implementation
// editors, who will write a temp file, then rename it to be the // editors, who will write a temp file, then rename it to be the
// actual file you wrote. So listen for that too. // actual file you wrote. So listen for that too.
wil::FolderChangeEvents::FileName | wil::FolderChangeEvents::LastWriteTime, wil::FolderChangeEvents::FileName | wil::FolderChangeEvents::LastWriteTime,
[this, settingsBasename = settingsPath.filename(), stateBasename = statePath.filename()](wil::FolderChangeEvent, PCWSTR fileModified) { [this, settingsBasename = settingsPath.filename()](wil::FolderChangeEvent, PCWSTR fileModified) {
const auto modifiedBasename = std::filesystem::path{ fileModified }.filename(); // DO NOT create a static reference to ApplicationState::SharedInstance here.
//
// ApplicationState::SharedInstance already caches its own
// static ref. If _we_ keep a static ref to the member in
// AppState, then our reference will keep ApplicationState alive
// after the `ActionToStringMap` gets cleaned up. Then, when we
// try to persist the actions in the window state, we won't be
// able to. We'll try to look up the action and the map just
// won't exist. We'll explode, even though the Terminal is
// tearing down anyways. So we'll just die, but still invoke
// WinDBG's post-mortem debugger, who won't be able to attach to
// the process that's already exiting.
//
// So DON'T ~give a mouse a cookie~ take a static ref here.
const winrt::hstring modifiedBasename{ std::filesystem::path{ fileModified }.filename().c_str() };
if (modifiedBasename == settingsBasename) if (modifiedBasename == settingsBasename)
{ {
_reloadSettings->Run(); _reloadSettings->Run();
} }
else if (modifiedBasename == stateBasename) else if (ApplicationState::SharedInstance().IsStatePath(modifiedBasename))
{ {
_reloadState(); _reloadState();
} }
@ -1051,6 +1037,11 @@ namespace winrt::TerminalApp::implementation
_SettingsChangedHandlers(*this, nullptr); _SettingsChangedHandlers(*this, nullptr);
} }
void AppLogic::_OpenSettingsUI()
{
_root->OpenSettingsUI();
}
// Method Description: // Method Description:
// - Returns a pointer to the global shared settings. // - Returns a pointer to the global shared settings.
[[nodiscard]] CascadiaSettings AppLogic::GetSettings() const noexcept [[nodiscard]] CascadiaSettings AppLogic::GetSettings() const noexcept
@ -1557,6 +1548,11 @@ namespace winrt::TerminalApp::implementation
return _root->IsQuakeWindow(); return _root->IsQuakeWindow();
} }
void AppLogic::RequestExitFullscreen()
{
_root->SetFullscreen(false);
}
bool AppLogic::GetMinimizeToNotificationArea() bool AppLogic::GetMinimizeToNotificationArea()
{ {
if constexpr (Feature_NotificationIcon::IsEnabled()) if constexpr (Feature_NotificationIcon::IsEnabled())

View file

@ -5,6 +5,7 @@
#include "AppLogic.g.h" #include "AppLogic.g.h"
#include "FindTargetWindowResult.g.h" #include "FindTargetWindowResult.g.h"
#include "SystemMenuChangeArgs.g.h"
#include "Jumplist.h" #include "Jumplist.h"
#include "LanguageProfileNotifier.h" #include "LanguageProfileNotifier.h"
#include "TerminalPage.h" #include "TerminalPage.h"
@ -35,6 +36,17 @@ namespace winrt::TerminalApp::implementation
FindTargetWindowResult(id, L""){}; FindTargetWindowResult(id, L""){};
}; };
struct SystemMenuChangeArgs : SystemMenuChangeArgsT<SystemMenuChangeArgs>
{
WINRT_PROPERTY(winrt::hstring, Name, L"");
WINRT_PROPERTY(SystemMenuChangeAction, Action, SystemMenuChangeAction::Add);
WINRT_PROPERTY(SystemMenuItemHandler, Handler, nullptr);
public:
SystemMenuChangeArgs(const winrt::hstring& name, SystemMenuChangeAction action, SystemMenuItemHandler handler = nullptr) :
_Name{ name }, _Action{ action }, _Handler{ handler } {};
};
struct AppLogic : AppLogicT<AppLogic, IInitializeWithWindow> struct AppLogic : AppLogicT<AppLogic, IInitializeWithWindow>
{ {
public: public:
@ -79,6 +91,7 @@ namespace winrt::TerminalApp::implementation
void SetPersistedLayoutIdx(const uint32_t idx); void SetPersistedLayoutIdx(const uint32_t idx);
void SetNumberOfOpenWindows(const uint64_t num); void SetNumberOfOpenWindows(const uint64_t num);
bool IsQuakeWindow() const noexcept; bool IsQuakeWindow() const noexcept;
void RequestExitFullscreen();
Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi); Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi);
bool CenterOnLaunch(); bool CenterOnLaunch();
@ -113,6 +126,7 @@ namespace winrt::TerminalApp::implementation
// -------------------------------- WinRT Events --------------------------------- // -------------------------------- WinRT Events ---------------------------------
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::ElementTheme); TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::ElementTheme);
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable); TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
private: private:
bool _isUwp{ false }; bool _isUwp{ false };
@ -163,6 +177,7 @@ namespace winrt::TerminalApp::implementation
void _RegisterSettingsChange(); void _RegisterSettingsChange();
fire_and_forget _DispatchReloadSettings(); fire_and_forget _DispatchReloadSettings();
void _ReloadSettings(); void _ReloadSettings();
void _OpenSettingsUI();
void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme); void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme);

View file

@ -19,6 +19,20 @@ namespace TerminalApp
String WindowName { get; }; String WindowName { get; };
}; };
delegate void SystemMenuItemHandler();
enum SystemMenuChangeAction
{
Add = 0,
Remove = 1
};
[default_interface] runtimeclass SystemMenuChangeArgs {
String Name { get; };
SystemMenuChangeAction Action { get; };
SystemMenuItemHandler Handler { get; };
};
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter [default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter
{ {
AppLogic(); AppLogic();
@ -60,6 +74,7 @@ namespace TerminalApp
void SetPersistedLayoutIdx(UInt32 idx); void SetPersistedLayoutIdx(UInt32 idx);
void SetNumberOfOpenWindows(UInt64 num); void SetNumberOfOpenWindows(UInt64 num);
void RenameFailed(); void RenameFailed();
void RequestExitFullscreen();
Boolean IsQuakeWindow(); Boolean IsQuakeWindow();
Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi); Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi);
@ -110,5 +125,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested; event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu; event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested; event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
} }
} }

View file

@ -2388,35 +2388,32 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
} }
// Method Description: // Method Description:
// - Split the focused pane in our tree of panes, and place the given // - The same as above, except this takes in the pane directly instead of a
// TermControl into the newly created pane. If we're the focused pane, then // profile and control to make a pane with
// we'll create two new children, and place them side-by-side in our Grid.
// Arguments: // Arguments:
// - splitType: what type of split we want to create. // - splitType: what type of split we want to create.
// - profile: The profile to associate with the newly created pane. // - splitSize: the desired size of the split
// - control: A TermControl to use in the new pane. // - newPane: the new pane
// Return Value: // Return Value:
// - The two newly created Panes, with the original pane first // - The two newly created Panes, with the original pane first
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitDirection splitType, std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitDirection splitType,
const float splitSize, const float splitSize,
const Profile& profile, std::shared_ptr<Pane> newPane)
const TermControl& control)
{ {
if (!_lastActive) if (!_lastActive)
{ {
if (_firstChild && _firstChild->_HasFocusedChild()) if (_firstChild && _firstChild->_HasFocusedChild())
{ {
return _firstChild->Split(splitType, splitSize, profile, control); return _firstChild->Split(splitType, splitSize, newPane);
} }
else if (_secondChild && _secondChild->_HasFocusedChild()) else if (_secondChild && _secondChild->_HasFocusedChild())
{ {
return _secondChild->Split(splitType, splitSize, profile, control); return _secondChild->Split(splitType, splitSize, newPane);
} }
return { nullptr, nullptr }; return { nullptr, nullptr };
} }
auto newPane = std::make_shared<Pane>(profile, control);
return _Split(splitType, splitSize, newPane); return _Split(splitType, splitSize, newPane);
} }

View file

@ -110,8 +110,7 @@ public:
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType, std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize, const float splitSize,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, std::shared_ptr<Pane> pane);
const winrt::Microsoft::Terminal::Control::TermControl& control);
bool ToggleSplitOrientation(); bool ToggleSplitOrientation();
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateAutoSplit(const std::shared_ptr<Pane> target, std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateAutoSplit(const std::shared_ptr<Pane> target,

View file

@ -68,7 +68,7 @@ namespace winrt::TerminalApp::implementation
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) }; const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) }; const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
_CreateNewTabWithProfileAndSettings(profile, settings, existingConnection); _CreateNewTabFromPane(_MakePane(newTerminalArgs, false, existingConnection));
const uint32_t tabCount = _tabs.Size(); const uint32_t tabCount = _tabs.Size();
const bool usedManualProfile = (newTerminalArgs != nullptr) && const bool usedManualProfile = (newTerminalArgs != nullptr) &&
@ -244,58 +244,6 @@ namespace winrt::TerminalApp::implementation
_InitializeTab(newTabImpl); _InitializeTab(newTabImpl);
} }
// Method Description:
// - Creates a new tab with the given settings. If the tab bar is not being
// currently displayed, it will be shown.
// Arguments:
// - profile: profile settings for this connection
// - settings: the TerminalSettings object to use to create the TerminalControl with.
// - existingConnection: optionally receives a connection from the outside world instead of attempting to create one
void TerminalPage::_CreateNewTabWithProfileAndSettings(const Profile& profile, const TerminalSettingsCreateResult& settings, TerminalConnection::ITerminalConnection existingConnection)
{
// Initialize the new tab
// Create a connection based on the values in our settings object if we weren't given one.
auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, settings.DefaultSettings());
// If we had an `existingConnection`, then this is an inbound handoff from somewhere else.
// We need to tell it about our size information so it can match the dimensions of what
// we are about to present.
if (existingConnection)
{
connection.Resize(settings.DefaultSettings().InitialRows(), settings.DefaultSettings().InitialCols());
}
TerminalConnection::ITerminalConnection debugConnection{ nullptr };
if (_settings.GlobalSettings().DebugFeaturesEnabled())
{
const CoreWindow window = CoreWindow::GetForCurrentThread();
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
if (bothAltsPressed)
{
std::tie(connection, debugConnection) = OpenDebugTapConnection(connection);
}
}
// Give term control a child of the settings so that any overrides go in the child
// This way, when we do a settings reload we just update the parent and the overrides remain
auto term = _InitControl(settings, connection);
auto newTabImpl = winrt::make_self<TerminalTab>(profile, term);
_RegisterTerminalEvents(term);
_InitializeTab(newTabImpl);
if (debugConnection) // this will only be set if global debugging is on and tap is active
{
auto newControl = _InitControl(settings, debugConnection);
_RegisterTerminalEvents(newControl);
// Split (auto) with the debug tap.
newTabImpl->SplitPane(SplitDirection::Automatic, 0.5f, profile, newControl);
}
}
// Method Description: // Method Description:
// - Get the icon of the currently focused terminal control, and set its // - Get the icon of the currently focused terminal control, and set its
// tab's icon to that icon. // tab's icon to that icon.
@ -365,28 +313,14 @@ namespace winrt::TerminalApp::implementation
// In the future, it may be preferable to just duplicate the // In the future, it may be preferable to just duplicate the
// current control's live settings (which will include changes // current control's live settings (which will include changes
// made through VT). // made through VT).
_CreateNewTabFromPane(_MakePane(nullptr, true, nullptr));
if (auto profile = tab.GetFocusedProfile()) const auto runtimeTabText{ tab.GetTabText() };
if (!runtimeTabText.empty())
{ {
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this. if (auto newTab{ _GetFocusedTabImpl() })
profile = GetClosestProfileForDuplicationOfProfile(profile);
const auto settingsCreateResult{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{ {
settingsCreateResult.DefaultSettings().StartingDirectory(workingDirectory); newTab->SetTabText(runtimeTabText);
}
_CreateNewTabWithProfileAndSettings(profile, settingsCreateResult);
const auto runtimeTabText{ tab.GetTabText() };
if (!runtimeTabText.empty())
{
if (auto newTab{ _GetFocusedTabImpl() })
{
newTab->SetTabText(runtimeTabText);
}
} }
} }
} }
@ -402,7 +336,7 @@ namespace winrt::TerminalApp::implementation
try try
{ {
_SetFocusedTab(tab); _SetFocusedTab(tab);
_SplitPane(tab, SplitDirection::Automatic, SplitType::Duplicate); _SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
} }
CATCH_LOG(); CATCH_LOG();
} }

View file

@ -300,10 +300,7 @@ namespace winrt::TerminalApp::implementation
// - true if the ApplicationState should be used. // - true if the ApplicationState should be used.
bool TerminalPage::ShouldUsePersistedLayout(CascadiaSettings& settings) const bool TerminalPage::ShouldUsePersistedLayout(CascadiaSettings& settings) const
{ {
// GH#5000 Until there is a separate state file for elevated sessions we should just not
// save at all while in an elevated window.
return Feature_PersistedWindowLayout::IsEnabled() && return Feature_PersistedWindowLayout::IsEnabled() &&
!IsElevated() &&
settings.GlobalSettings().FirstWindowPreference() == FirstWindowPreference::PersistedWindowLayout; settings.GlobalSettings().FirstWindowPreference() == FirstWindowPreference::PersistedWindowLayout;
} }
@ -850,14 +847,7 @@ namespace winrt::TerminalApp::implementation
WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) && WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down); WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
if (altPressed && !debugTap) if (shiftPressed && !debugTap)
{
this->_SplitPane(SplitDirection::Automatic,
SplitType::Manual,
0.5f,
newTerminalArgs);
}
else if (shiftPressed && !debugTap)
{ {
// Manually fill in the evaluated profile. // Manually fill in the evaluated profile.
if (newTerminalArgs.ProfileIndex() != nullptr) if (newTerminalArgs.ProfileIndex() != nullptr)
@ -873,7 +863,17 @@ namespace winrt::TerminalApp::implementation
} }
else else
{ {
LOG_IF_FAILED(this->_OpenNewTab(newTerminalArgs)); const auto newPane = _MakePane(newTerminalArgs);
if (altPressed && !debugTap)
{
this->_SplitPane(SplitDirection::Automatic,
0.5f,
newPane);
}
else
{
_CreateNewTabFromPane(newPane);
}
} }
} }
@ -1485,18 +1485,15 @@ namespace winrt::TerminalApp::implementation
// Method Description: // Method Description:
// - Split the focused pane either horizontally or vertically, and place the // - Split the focused pane either horizontally or vertically, and place the
// given TermControl into the newly created pane. // given pane accordingly in the tree
// Arguments: // Arguments:
// - newPane: the pane to add to our tree of panes
// - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the // - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the
// new pane should be split from its parent. // new pane should be split from its parent.
// - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane. // - splitSize: the size of the split
// - newTerminalArgs: An object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
void TerminalPage::_SplitPane(const SplitDirection splitDirection, void TerminalPage::_SplitPane(const SplitDirection splitDirection,
const SplitType splitMode,
const float splitSize, const float splitSize,
const NewTerminalArgs& newTerminalArgs) std::shared_ptr<Pane> newPane)
{ {
const auto focusedTab{ _GetFocusedTabImpl() }; const auto focusedTab{ _GetFocusedTabImpl() };
@ -1506,104 +1503,52 @@ namespace winrt::TerminalApp::implementation
return; return;
} }
_SplitPane(*focusedTab, splitDirection, splitMode, splitSize, newTerminalArgs); _SplitPane(*focusedTab, splitDirection, splitSize, newPane);
} }
// Method Description: // Method Description:
// - Split the focused pane of the given tab, either horizontally or vertically, and place the // - Split the focused pane of the given tab, either horizontally or vertically, and place the
// given TermControl into the newly created pane. // given pane accordingly
// Arguments: // Arguments:
// - tab: The tab that is going to be split. // - tab: The tab that is going to be split.
// - newPane: the pane to add to our tree of panes
// - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the // - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the
// new pane should be split from its parent. // new pane should be split from its parent.
// - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane. // - splitSize: the size of the split
// - newTerminalArgs: An object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
void TerminalPage::_SplitPane(TerminalTab& tab, void TerminalPage::_SplitPane(TerminalTab& tab,
const SplitDirection splitDirection, const SplitDirection splitDirection,
const SplitType splitMode,
const float splitSize, const float splitSize,
const NewTerminalArgs& newTerminalArgs) std::shared_ptr<Pane> newPane)
{ {
try const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
const float contentHeight = ::base::saturated_cast<float>(_tabContent.ActualHeight());
const winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight };
auto realSplitType = splitDirection;
if (realSplitType == SplitDirection::Automatic)
{ {
TerminalSettingsCreateResult controlSettings{ nullptr }; realSplitType = tab.PreCalculateAutoSplit(availableSpace);
Profile profile{ nullptr }; }
if (splitMode == SplitType::Duplicate) const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
if (!canSplit)
{
return;
}
_UnZoomIfNeeded();
tab.SplitPane(realSplitType, splitSize, newPane);
// After GH#6586, the control will no longer focus itself
// automatically when it's finished being laid out. Manually focus
// the control here instead.
if (_startupState == StartupState::Initialized)
{
if (const auto control = _GetActiveControl())
{ {
profile = tab.GetFocusedProfile(); control.Focus(FocusState::Programmatic);
if (profile)
{
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
}
}
// TODO: GH#5047 - In the future, we should get the Profile of
// the focused pane, and use that to build a new instance of the
// settings so we can duplicate this tab/pane.
//
// Currently, if the profile doesn't exist anymore in our
// settings, we'll silently do nothing.
//
// In the future, it will be preferable to just duplicate the
// current control's settings, but we can't do that currently,
// because we won't be able to create a new instance of the
// connection without keeping an instance of the original Profile
// object around.
}
if (!profile)
{
profile = _settings.GetProfileForArgs(newTerminalArgs);
controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings);
}
const auto controlConnection = _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings());
const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
const float contentHeight = ::base::saturated_cast<float>(_tabContent.ActualHeight());
const winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight };
auto realSplitType = splitDirection;
if (realSplitType == SplitDirection::Automatic)
{
realSplitType = tab.PreCalculateAutoSplit(availableSpace);
}
const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
if (!canSplit)
{
return;
}
auto newControl = _InitControl(controlSettings, controlConnection);
// Hookup our event handlers to the new terminal
_RegisterTerminalEvents(newControl);
_UnZoomIfNeeded();
tab.SplitPane(realSplitType, splitSize, profile, newControl);
// After GH#6586, the control will no longer focus itself
// automatically when it's finished being laid out. Manually focus
// the control here instead.
if (_startupState == StartupState::Initialized)
{
if (const auto control = _GetActiveControl())
{
control.Focus(FocusState::Programmatic);
}
} }
} }
CATCH_LOG();
} }
// Method Description: // Method Description:
@ -2111,7 +2056,7 @@ namespace winrt::TerminalApp::implementation
{ {
if (target == SettingsTarget::SettingsUI) if (target == SettingsTarget::SettingsUI)
{ {
_OpenSettingsUI(); OpenSettingsUI();
} }
else else
{ {
@ -2188,6 +2133,96 @@ namespace winrt::TerminalApp::implementation
return term; return term;
} }
// Method Description:
// - Creates a pane and returns a shared_ptr to it
// - The caller should handle where the pane goes after creation,
// either to split an already existing pane or to create a new tab with it
// Arguments:
// - newTerminalArgs: an object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
// - duplicate: a boolean to indicate whether the pane we create should be
// a duplicate of the currently focused pane
// - existingConnection: optionally receives a connection from the outside
// world instead of attempting to create one
std::shared_ptr<Pane> TerminalPage::_MakePane(const NewTerminalArgs& newTerminalArgs, const bool duplicate, TerminalConnection::ITerminalConnection existingConnection)
{
TerminalSettingsCreateResult controlSettings{ nullptr };
Profile profile{ nullptr };
if (duplicate)
{
const auto focusedTab{ _GetFocusedTabImpl() };
if (focusedTab)
{
profile = focusedTab->GetFocusedProfile();
if (profile)
{
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
}
}
}
}
if (!profile)
{
profile = _settings.GetProfileForArgs(newTerminalArgs);
controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings);
}
auto connection = existingConnection ? existingConnection : _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings());
if (existingConnection)
{
connection.Resize(controlSettings.DefaultSettings().InitialRows(), controlSettings.DefaultSettings().InitialCols());
}
TerminalConnection::ITerminalConnection debugConnection{ nullptr };
if (_settings.GlobalSettings().DebugFeaturesEnabled())
{
const CoreWindow window = CoreWindow::GetForCurrentThread();
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
if (bothAltsPressed)
{
std::tie(connection, debugConnection) = OpenDebugTapConnection(connection);
}
}
const auto control = _InitControl(controlSettings, connection);
_RegisterTerminalEvents(control);
auto resultPane = std::make_shared<Pane>(profile, control);
if (debugConnection) // this will only be set if global debugging is on and tap is active
{
auto newControl = _InitControl(controlSettings, debugConnection);
_RegisterTerminalEvents(newControl);
// Split (auto) with the debug tap.
auto debugPane = std::make_shared<Pane>(profile, newControl);
// Since we're doing this split directly on the pane (instead of going through TerminalTab,
// we need to handle the panes 'active' states
// Set the pane we're splitting to active (otherwise Split will not do anything)
resultPane->SetActive();
auto [original, _] = resultPane->Split(SplitDirection::Automatic, 0.5f, debugPane);
// Set the non-debug pane as active
resultPane->ClearActive();
original->SetActive();
}
return resultPane;
}
// Method Description: // Method Description:
// - Hook up keybindings, and refresh the UI of the terminal. // - Hook up keybindings, and refresh the UI of the terminal.
// This includes update the settings of all the tabs according // This includes update the settings of all the tabs according
@ -2497,9 +2532,7 @@ namespace winrt::TerminalApp::implementation
// - <none> // - <none>
void TerminalPage::ToggleFullscreen() void TerminalPage::ToggleFullscreen()
{ {
_isFullscreen = !_isFullscreen; SetFullscreen(!_isFullscreen);
_UpdateTabView();
_FullscreenChangedHandlers(*this, nullptr);
} }
// Method Description: // Method Description:
@ -2716,6 +2749,17 @@ namespace winrt::TerminalApp::implementation
return _isAlwaysOnTop; return _isAlwaysOnTop;
} }
void TerminalPage::SetFullscreen(bool newFullscreen)
{
if (_isFullscreen == newFullscreen)
{
return;
}
_isFullscreen = newFullscreen;
_UpdateTabView();
_FullscreenChangedHandlers(*this, nullptr);
}
HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection) HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection)
{ {
// We need to be on the UI thread in order for _OpenNewTab to run successfully. // We need to be on the UI thread in order for _OpenNewTab to run successfully.
@ -2743,7 +2787,7 @@ namespace winrt::TerminalApp::implementation
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) }; const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
const auto settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) }; const auto settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
_CreateNewTabWithProfileAndSettings(profile, settings, connection); _CreateNewTabFromPane(_MakePane(newTerminalArgs, false, connection));
// Request a summon of this window to the foreground // Request a summon of this window to the foreground
_SummonWindowRequestedHandlers(*this, nullptr); _SummonWindowRequestedHandlers(*this, nullptr);
@ -2759,7 +2803,7 @@ namespace winrt::TerminalApp::implementation
// - <none> // - <none>
// Return Value: // Return Value:
// - <none> // - <none>
void TerminalPage::_OpenSettingsUI() void TerminalPage::OpenSettingsUI()
{ {
// If we're holding the settings tab's switch command, don't create a new one, switch to the existing one. // If we're holding the settings tab's switch command, don't create a new one, switch to the existing one.
if (!_settingsTab) if (!_settingsTab)
@ -3377,7 +3421,7 @@ namespace winrt::TerminalApp::implementation
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipInteracted", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage)); TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipInteracted", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
_OpenSettingsUI(); OpenSettingsUI();
} }
// Method Description: // Method Description:

View file

@ -83,6 +83,7 @@ namespace winrt::TerminalApp::implementation
bool FocusMode() const; bool FocusMode() const;
bool Fullscreen() const; bool Fullscreen() const;
bool AlwaysOnTop() const; bool AlwaysOnTop() const;
void SetFullscreen(bool);
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions); void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
@ -121,6 +122,8 @@ namespace winrt::TerminalApp::implementation
bool IsQuakeWindow() const noexcept; bool IsQuakeWindow() const noexcept;
bool IsElevated() const noexcept; bool IsElevated() const noexcept;
void OpenSettingsUI();
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
// -------------------------------- WinRT Events --------------------------------- // -------------------------------- WinRT Events ---------------------------------
@ -209,7 +212,6 @@ namespace winrt::TerminalApp::implementation
void _OpenNewTabDropdown(); void _OpenNewTabDropdown();
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr); HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _CreateNewTabFromPane(std::shared_ptr<Pane> pane); void _CreateNewTabFromPane(std::shared_ptr<Pane> pane);
void _CreateNewTabWithProfileAndSettings(const Microsoft::Terminal::Settings::Model::Profile& profile, const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings); winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(Microsoft::Terminal::Settings::Model::Profile profile, Microsoft::Terminal::Settings::Model::TerminalSettings settings);
winrt::fire_and_forget _OpenNewWindow(const bool elevate, const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs); winrt::fire_and_forget _OpenNewWindow(const bool elevate, const Microsoft::Terminal::Settings::Model::NewTerminalArgs newTerminalArgs);
@ -297,14 +299,12 @@ namespace winrt::TerminalApp::implementation
void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll); void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll);
void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitDirection splitType, void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, const float splitSize,
const float splitSize = 0.5f, std::shared_ptr<Pane> newPane);
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
void _SplitPane(TerminalTab& tab, void _SplitPane(TerminalTab& tab,
const Microsoft::Terminal::Settings::Model::SplitDirection splitType, const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, const float splitSize,
const float splitSize = 0.5f, std::shared_ptr<Pane> newPane);
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction); void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
void _ToggleSplitOrientation(); void _ToggleSplitOrientation();
@ -351,6 +351,10 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection); const winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection& connection);
std::shared_ptr<Pane> _MakePane(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr,
const bool duplicate = false,
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _RefreshUIForSettingsReload(); void _RefreshUIForSettingsReload();
void _SetNonClientAreaColors(const Windows::UI::Color& selectedTabColor); void _SetNonClientAreaColors(const Windows::UI::Color& selectedTabColor);
@ -366,8 +370,6 @@ namespace winrt::TerminalApp::implementation
void _UnZoomIfNeeded(); void _UnZoomIfNeeded();
void _OpenSettingsUI();
static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll); static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll);
static uint32_t _ReadSystemRowsToScroll(); static uint32_t _ReadSystemRowsToScroll();

View file

@ -153,7 +153,7 @@
</ContentDialog> </ContentDialog>
<local:CommandPalette x:Name="CommandPalette" <local:CommandPalette x:Name="CommandPalette"
Grid.Row="1" Grid.Row="2"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
PreviewKeyDown="_KeyDownHandler" PreviewKeyDown="_KeyDownHandler"
Visibility="Collapsed" /> Visibility="Collapsed" />

View file

@ -25,18 +25,6 @@ namespace winrt
namespace winrt::TerminalApp::implementation namespace winrt::TerminalApp::implementation
{ {
TerminalTab::TerminalTab(const Profile& profile, const TermControl& control)
{
_rootPane = std::make_shared<Pane>(profile, control, true);
_rootPane->Id(_nextPaneId);
_activePane = _rootPane;
_mruPanes.insert(_mruPanes.begin(), _nextPaneId);
++_nextPaneId;
_Setup();
}
TerminalTab::TerminalTab(std::shared_ptr<Pane> rootPane) TerminalTab::TerminalTab(std::shared_ptr<Pane> rootPane)
{ {
_rootPane = rootPane; _rootPane = rootPane;
@ -64,8 +52,9 @@ namespace winrt::TerminalApp::implementation
// focus the first one. // focus the first one.
if (_activePane == nullptr) if (_activePane == nullptr)
{ {
_rootPane->FocusPane(firstId); const auto firstPane = _rootPane->FindPane(firstId);
_activePane = _rootPane->GetActivePane(); firstPane->SetActive();
_activePane = firstPane;
} }
// If the focused pane is a leaf, add it to the MRU panes // If the focused pane is a leaf, add it to the MRU panes
if (const auto id = _activePane->Id()) if (const auto id = _activePane->Id())
@ -503,39 +492,48 @@ namespace winrt::TerminalApp::implementation
// Method Description: // Method Description:
// - Split the focused pane in our tree of panes, and place the // - Split the focused pane in our tree of panes, and place the
// given TermControl into the newly created pane. // given pane into the tree of panes according to the split
// Arguments: // Arguments:
// - splitType: The type of split we want to create. // - splitType: The type of split we want to create
// - profile: The profile GUID to associate with the newly created pane. // - splitSize: The size of the split we want to create
// - control: A TermControl to use in the new pane. // - pane: The new pane to add to the tree of panes; note that this pane
// could itself be a parent pane/the root node of a tree of panes
// Return Value: // Return Value:
// - <none> // - <none>
void TerminalTab::SplitPane(SplitDirection splitType, void TerminalTab::SplitPane(SplitDirection splitType,
const float splitSize, const float splitSize,
const Profile& profile, std::shared_ptr<Pane> pane)
TermControl& control)
{ {
// Add the new event handlers to the new pane(s)
// and update their ids.
pane->WalkTree([&](auto p) {
_AttachEventHandlersToPane(p);
if (p->_IsLeaf())
{
p->Id(_nextPaneId);
_AttachEventHandlersToControl(p->Id().value(), p->_control);
_nextPaneId++;
}
return false;
});
// Make sure to take the ID before calling Split() - Split() will clear out the active pane's ID // Make sure to take the ID before calling Split() - Split() will clear out the active pane's ID
const auto activePaneId = _activePane->Id(); const auto activePaneId = _activePane->Id();
// Depending on which direction will be split, the new pane can be // Depending on which direction will be split, the new pane can be
// either the first or second child, but this will always return the // either the first or second child, but this will always return the
// original pane first. // original pane first.
auto [original, newPane] = _activePane->Split(splitType, splitSize, profile, control); auto [original, newPane] = _activePane->Split(splitType, splitSize, pane);
// The active pane has an id if it is a leaf // The active pane has an id if it is a leaf
if (activePaneId) if (activePaneId)
{ {
original->Id(activePaneId.value()); original->Id(activePaneId.value());
} }
newPane->Id(_nextPaneId);
++_nextPaneId;
_activePane = original; _activePane = original;
// Add a event handlers to the new panes' GotFocus event. When the pane // Add a event handlers to the new panes' GotFocus event. When the pane
// gains focus, we'll mark it as the new active pane. // gains focus, we'll mark it as the new active pane.
_AttachEventHandlersToControl(newPane->Id().value(), control);
_AttachEventHandlersToPane(original); _AttachEventHandlersToPane(original);
_AttachEventHandlersToPane(newPane);
// Immediately update our tracker of the focused pane now. If we're // Immediately update our tracker of the focused pane now. If we're
// splitting panes during startup (from a commandline), then it's // splitting panes during startup (from a commandline), then it's

View file

@ -21,7 +21,6 @@ namespace winrt::TerminalApp::implementation
struct TerminalTab : TerminalTabT<TerminalTab, TabBase> struct TerminalTab : TerminalTabT<TerminalTab, TabBase>
{ {
public: public:
TerminalTab(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, const winrt::Microsoft::Terminal::Control::TermControl& control);
TerminalTab(std::shared_ptr<Pane> rootPane); TerminalTab(std::shared_ptr<Pane> rootPane);
// Called after construction to perform the necessary setup, which relies on weak_ptr // Called after construction to perform the necessary setup, which relies on weak_ptr
@ -40,8 +39,7 @@ namespace winrt::TerminalApp::implementation
void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType, void SplitPane(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize, const float splitSize,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, std::shared_ptr<Pane> newPane);
winrt::Microsoft::Terminal::Control::TermControl& control);
void ToggleSplitOrientation(); void ToggleSplitOrientation();
winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath); winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath);

View file

@ -429,8 +429,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// EXIT POINT // EXIT POINT
const auto hr = wil::ResultFromCaughtException(); const auto hr = wil::ResultFromCaughtException();
// GH#11556 - make sure to format the error code to this string as an UNSIGNED int
winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") }, winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") },
fmt::format(_errorFormat, hr), fmt::format(_errorFormat, static_cast<unsigned int>(hr)),
_commandline) }; _commandline) };
_TerminalOutputHandlers(failureText); _TerminalOutputHandlers(failureText);
@ -457,6 +458,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{ {
try try
{ {
// GH#11556 - make sure to format the error code to this string as an UNSIGNED int
winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, fmt::format(_errorFormat, status)) }; winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, fmt::format(_errorFormat, status)) };
_TerminalOutputHandlers(L"\r\n"); _TerminalOutputHandlers(L"\r\n");
_TerminalOutputHandlers(exitText); _TerminalOutputHandlers(exitText);

View file

@ -3,16 +3,18 @@
#include "pch.h" #include "pch.h"
#include "ControlCore.h" #include "ControlCore.h"
#include <argb.h>
#include <DefaultSettings.h> #include <DefaultSettings.h>
#include <unicode.hpp> #include <unicode.hpp>
#include <Utf16Parser.hpp> #include <Utf16Parser.hpp>
#include <Utils.h>
#include <WinUser.h> #include <WinUser.h>
#include <LibraryResources.h> #include <LibraryResources.h>
#include "EventArgs.h"
#include "../../types/inc/GlyphWidth.hpp" #include "../../types/inc/GlyphWidth.hpp"
#include "../../types/inc/Utils.hpp"
#include "../../buffer/out/search.h" #include "../../buffer/out/search.h"
#include "../../renderer/atlas/AtlasEngine.h"
#include "../../renderer/dx/DxRenderer.hpp"
#include "ControlCore.g.cpp" #include "ControlCore.g.cpp"
@ -202,6 +204,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const double actualHeight, const double actualHeight,
const double compositionScale) const double compositionScale)
{ {
assert(_settings);
_panelWidth = actualWidth; _panelWidth = actualWidth;
_panelHeight = actualHeight; _panelHeight = actualHeight;
_compositionScale = compositionScale; _compositionScale = compositionScale;
@ -222,10 +226,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return false; return false;
} }
// Set up the DX Engine if (Feature_AtlasEngine::IsEnabled() && _settings.UseAtlasEngine())
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>(); {
_renderer->AddRenderEngine(dxEngine.get()); _renderEngine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
_renderEngine = std::move(dxEngine); }
else
{
_renderEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
}
_renderer->AddRenderEngine(_renderEngine.get());
// Initialize our font with the renderer // Initialize our font with the renderer
// We don't have to care about DPI. We'll get a change message immediately if it's not 96 // We don't have to care about DPI. We'll get a change message immediately if it's not 96
@ -271,11 +281,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering()); _renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
_renderEngine->SetIntenseIsBold(_settings.IntenseIsBold()); _renderEngine->SetIntenseIsBold(_settings.IntenseIsBold());
_updateAntiAliasingMode(_renderEngine.get()); _updateAntiAliasingMode();
// GH#5098: Inform the engine of the opacity of the default text background. // GH#5098: Inform the engine of the opacity of the default text background.
// GH#11315: Always do this, even if they don't have acrylic on. // GH#11315: Always do this, even if they don't have acrylic on.
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.Opacity())); const auto backgroundIsOpaque = _settings.Opacity() == 1.0 && _settings.BackgroundImage().empty();
_renderEngine->SetDefaultTextBackgroundOpacity(static_cast<float>(backgroundIsOpaque));
THROW_IF_FAILED(_renderEngine->Enable()); THROW_IF_FAILED(_renderEngine->Enable());
@ -616,7 +627,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering()); _renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering()); _renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
_updateAntiAliasingMode(_renderEngine.get()); _updateAntiAliasingMode();
// Refresh our font with the renderer // Refresh our font with the renderer
const auto actualFontOldSize = _actualFont.GetSize(); const auto actualFontOldSize = _actualFont.GetSize();
@ -650,22 +661,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
} }
} }
void ControlCore::_updateAntiAliasingMode(::Microsoft::Console::Render::DxEngine* const dxEngine) void ControlCore::_updateAntiAliasingMode()
{ {
// Update DxEngine's AntialiasingMode D2D1_TEXT_ANTIALIAS_MODE mode;
switch (_settings.AntialiasingMode()) switch (_settings.AntialiasingMode())
{ {
case TextAntialiasingMode::Cleartype: case TextAntialiasingMode::Cleartype:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE); mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
break; break;
case TextAntialiasingMode::Aliased: case TextAntialiasingMode::Aliased:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED); mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
break; break;
case TextAntialiasingMode::Grayscale:
default: default:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
break; break;
} }
_renderEngine->SetAntialiasingMode(mode);
} }
// Method Description: // Method Description:
@ -1296,7 +1309,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_renderEngine) if (_renderEngine)
{ {
auto lock = _terminal->LockForWriting(); auto lock = _terminal->LockForWriting();
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(opacity)); const auto backgroundIsOpaque = opacity == 1.0 && _settings.BackgroundImage().empty();
_renderEngine->SetDefaultTextBackgroundOpacity(static_cast<float>(backgroundIsOpaque));
} }
} }

View file

@ -15,11 +15,8 @@
#pragma once #pragma once
#include "EventArgs.h"
#include "ControlCore.g.h" #include "ControlCore.g.h"
#include "../../renderer/base/Renderer.hpp" #include "../../renderer/base/Renderer.hpp"
#include "../../renderer/dx/DxRenderer.hpp"
#include "../../renderer/uia/UiaRenderer.hpp"
#include "../../cascadia/TerminalCore/Terminal.hpp" #include "../../cascadia/TerminalCore/Terminal.hpp"
#include "../buffer/out/search.h" #include "../buffer/out/search.h"
#include "cppwinrt_utils.h" #include "cppwinrt_utils.h"
@ -188,7 +185,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// As _renderer has a dependency on _renderEngine (through a raw pointer) // As _renderer has a dependency on _renderEngine (through a raw pointer)
// we must ensure the _renderer is deallocated first. // we must ensure the _renderer is deallocated first.
// (C++ class members are destroyed in reverse order.) // (C++ class members are destroyed in reverse order.)
std::unique_ptr<::Microsoft::Console::Render::DxEngine> _renderEngine{ nullptr }; std::unique_ptr<::Microsoft::Console::Render::IRenderEngine> _renderEngine{ nullptr };
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr }; std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr };
IControlSettings _settings{ nullptr }; IControlSettings _settings{ nullptr };
@ -248,7 +245,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma endregion #pragma endregion
void _raiseReadOnlyWarning(); void _raiseReadOnlyWarning();
void _updateAntiAliasingMode(::Microsoft::Console::Render::DxEngine* const dxEngine); void _updateAntiAliasingMode();
void _connectionOutputHandler(const hstring& hstr); void _connectionOutputHandler(const hstring& hstr);
void _updateHoveredCell(const std::optional<til::point> terminalPosition); void _updateHoveredCell(const std::optional<til::point> terminalPosition);

View file

@ -22,6 +22,7 @@
#include "cppwinrt_utils.h" #include "cppwinrt_utils.h"
#include "ControlCore.h" #include "ControlCore.h"
#include "../../renderer/uia/UiaRenderer.hpp"
namespace ControlUnitTests namespace ControlUnitTests
{ {

View file

@ -27,10 +27,11 @@ namespace Microsoft.Terminal.Control
interface IControlSettings requires Microsoft.Terminal.Core.ICoreSettings, Microsoft.Terminal.Control.IControlAppearance interface IControlSettings requires Microsoft.Terminal.Core.ICoreSettings, Microsoft.Terminal.Control.IControlAppearance
{ {
String ProfileName; String ProfileName;
String ProfileSource;
Boolean UseAcrylic; Boolean UseAcrylic;
ScrollbarState ScrollState; ScrollbarState ScrollState;
Boolean UseAtlasEngine;
String FontFace; String FontFace;
Int32 FontSize; Int32 FontSize;
Windows.UI.Text.FontWeight FontWeight; Windows.UI.Text.FontWeight FontWeight;

View file

@ -3,17 +3,16 @@
#include "pch.h" #include "pch.h"
#include "TermControl.h" #include "TermControl.h"
#include <argb.h>
#include <DefaultSettings.h>
#include <unicode.hpp> #include <unicode.hpp>
#include <Utf16Parser.hpp> #include <Utf16Parser.hpp>
#include <Utils.h>
#include <LibraryResources.h> #include <LibraryResources.h>
#include "TermControlAutomationPeer.h"
#include "../../types/inc/GlyphWidth.hpp" #include "../../types/inc/GlyphWidth.hpp"
#include "../../types/inc/Utils.hpp" #include "../../renderer/atlas/AtlasEngine.h"
#include "TermControl.g.cpp" #include "TermControl.g.cpp"
#include "TermControlAutomationPeer.h"
using namespace ::Microsoft::Console::Types; using namespace ::Microsoft::Console::Types;
using namespace ::Microsoft::Console::VirtualTerminal; using namespace ::Microsoft::Console::VirtualTerminal;
@ -1828,13 +1827,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const winrt::Windows::Foundation::Size initialSize{ cols, rows }; const winrt::Windows::Foundation::Size initialSize{ cols, rows };
return GetProposedDimensions(initialSize, return GetProposedDimensions(settings, dpi, initialSize);
settings.FontSize(),
settings.FontWeight(),
settings.FontFace(),
settings.ScrollState(),
settings.Padding(),
dpi);
} }
// Function Description: // Function Description:
@ -1855,16 +1848,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// caller knows what monitor the control is about to appear on. // caller knows what monitor the control is about to appear on.
// Return Value: // Return Value:
// - a size containing the requested dimensions in pixels. // - a size containing the requested dimensions in pixels.
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(const winrt::Windows::Foundation::Size& initialSizeInChars, winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars)
const int32_t& fontHeight,
const winrt::Windows::UI::Text::FontWeight& fontWeight,
const winrt::hstring& fontFace,
const ScrollbarState& scrollState,
const winrt::hstring& padding,
const uint32_t dpi)
{ {
const auto cols = ::base::saturated_cast<int>(initialSizeInChars.Width); const auto cols = ::base::saturated_cast<int>(initialSizeInChars.Width);
const auto rows = ::base::saturated_cast<int>(initialSizeInChars.Height); const auto rows = ::base::saturated_cast<int>(initialSizeInChars.Height);
const auto fontSize = settings.FontSize();
const auto fontWeight = settings.FontWeight();
const auto fontFace = settings.FontFace();
const auto scrollState = settings.ScrollState();
const auto padding = settings.Padding();
// Initialize our font information. // Initialize our font information.
// The font width doesn't terribly matter, we'll only be using the // The font width doesn't terribly matter, we'll only be using the
@ -1873,28 +1865,39 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// The family is only used to determine if the font is truetype or // The family is only used to determine if the font is truetype or
// not, but DX doesn't use that info at all. // not, but DX doesn't use that info at all.
// The Codepage is additionally not actually used by the DX engine at all. // The Codepage is additionally not actually used by the DX engine at all.
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, gsl::narrow_cast<short>(fontHeight) }, CP_UTF8, false }; FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, gsl::narrow_cast<short>(fontSize) }, CP_UTF8, false };
FontInfoDesired desiredFont = { actualFont }; FontInfoDesired desiredFont = { actualFont };
// Create a DX engine and initialize it with our font and DPI. We'll // Create a DX engine and initialize it with our font and DPI. We'll
// then use it to measure how much space the requested rows and columns // then use it to measure how much space the requested rows and columns
// will take up. // will take up.
// TODO: MSFT:21254947 - use a static function to do this instead of // TODO: MSFT:21254947 - use a static function to do this instead of
// instantiating a DxEngine // instantiating a DxEngine/AtlasEngine.
// GH#10211 - UNDER NO CIRCUMSTANCE should this fail. If it does, the // GH#10211 - UNDER NO CIRCUMSTANCE should this fail. If it does, the
// whole app will crash instantaneously on launch, which is no good. // whole app will crash instantaneously on launch, which is no good.
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>(); double scale;
LOG_IF_FAILED(dxEngine->UpdateDpi(dpi)); if (Feature_AtlasEngine::IsEnabled() && settings.UseAtlasEngine())
LOG_IF_FAILED(dxEngine->UpdateFont(desiredFont, actualFont)); {
auto engine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
LOG_IF_FAILED(engine->UpdateDpi(dpi));
LOG_IF_FAILED(engine->UpdateFont(desiredFont, actualFont));
scale = engine->GetScaling();
}
else
{
auto engine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
LOG_IF_FAILED(engine->UpdateDpi(dpi));
LOG_IF_FAILED(engine->UpdateFont(desiredFont, actualFont));
scale = engine->GetScaling();
}
const auto scale = dxEngine->GetScaling(); const auto actualFontSize = actualFont.GetSize();
const auto fontSize = actualFont.GetSize();
// UWP XAML scrollbars aren't guaranteed to be the same size as the // UWP XAML scrollbars aren't guaranteed to be the same size as the
// ComCtl scrollbars, but it's certainly close enough. // ComCtl scrollbars, but it's certainly close enough.
const auto scrollbarSize = GetSystemMetricsForDpi(SM_CXVSCROLL, dpi); const auto scrollbarSize = GetSystemMetricsForDpi(SM_CXVSCROLL, dpi);
double width = cols * fontSize.X; double width = cols * actualFontSize.X;
// Reserve additional space if scrollbar is intended to be visible // Reserve additional space if scrollbar is intended to be visible
if (scrollState == ScrollbarState::Visible) if (scrollState == ScrollbarState::Visible)
@ -1902,7 +1905,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
width += scrollbarSize; width += scrollbarSize;
} }
double height = rows * fontSize.Y; double height = rows * actualFontSize.Y;
const auto thickness = ParseThicknessFromPadding(padding); const auto thickness = ParseThicknessFromPadding(padding);
// GH#2061 - make sure to account for the size the padding _will be_ scaled to // GH#2061 - make sure to account for the size the padding _will be_ scaled to
width += scale * (thickness.Left + thickness.Right); width += scale * (thickness.Left + thickness.Right);
@ -1962,13 +1965,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const winrt::Windows::Foundation::Size minSize{ 1, 1 }; const winrt::Windows::Foundation::Size minSize{ 1, 1 };
const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel(); const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
const auto dpi = ::base::saturated_cast<uint32_t>(USER_DEFAULT_SCREEN_DPI * scaleFactor); const auto dpi = ::base::saturated_cast<uint32_t>(USER_DEFAULT_SCREEN_DPI * scaleFactor);
return GetProposedDimensions(minSize, return GetProposedDimensions(_settings, dpi, minSize);
_settings.FontSize(),
_settings.FontWeight(),
_settings.FontFace(),
_settings.ScrollState(),
_settings.Padding(),
dpi);
} }
} }
@ -2271,6 +2268,42 @@ namespace winrt::Microsoft::Terminal::Control::implementation
} }
std::wstring fullPath{ item.Path() }; std::wstring fullPath{ item.Path() };
// Fix path for WSL
if (_settings.ProfileSource() == L"Windows.Terminal.Wsl")
{
std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/');
if (fullPath.size() >= 2 && fullPath.at(1) == L':')
{
// C:/foo/bar -> Cc/foo/bar
fullPath.at(1) = til::tolower_ascii(fullPath.at(0));
// Cc/foo/bar -> /mnt/c/foo/bar
fullPath.replace(0, 1, L"/mnt/");
}
else
{
static constexpr std::wstring_view wslPathPrefixes[] = { L"//wsl.localhost/", L"//wsl$/" };
for (auto prefix : wslPathPrefixes)
{
if (til::starts_with(fullPath, prefix))
{
if (const auto idx = fullPath.find(L'/', prefix.size()); idx != std::wstring::npos)
{
// //wsl.localhost/Ubuntu-18.04/foo/bar -> /foo/bar
fullPath.erase(0, idx);
}
else
{
// //wsl.localhost/Ubuntu-18.04 -> /
fullPath = L"/";
}
break;
}
}
}
}
const auto containsSpaces = std::find(fullPath.begin(), const auto containsSpaces = std::find(fullPath.begin(),
fullPath.end(), fullPath.end(),
L' ') != fullPath.end(); L' ') != fullPath.end();
@ -2283,6 +2316,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
allPaths += fullPath; allPaths += fullPath;
} }
_core.PasteText(winrt::hstring{ allPaths }); _core.PasteText(winrt::hstring{ allPaths });
} }
} }

View file

@ -92,13 +92,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void Settings(IControlSettings newSettings); void Settings(IControlSettings newSettings);
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi); static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi);
static Windows::Foundation::Size GetProposedDimensions(const winrt::Windows::Foundation::Size& initialSizeInChars, static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars);
const int32_t& fontSize,
const winrt::Windows::UI::Text::FontWeight& fontWeight,
const winrt::hstring& fontFace,
const ScrollbarState& scrollState,
const winrt::hstring& padding,
const uint32_t dpi);
void BellLightOn(); void BellLightOn();

View file

@ -147,6 +147,7 @@
<ProjectReference Include="..\..\types\lib\types.vcxproj" /> <ProjectReference Include="..\..\types\lib\types.vcxproj" />
<ProjectReference Include="..\..\buffer\out\lib\bufferout.vcxproj" /> <ProjectReference Include="..\..\buffer\out\lib\bufferout.vcxproj" />
<ProjectReference Include="$(OpenConsoleDir)src\renderer\base\lib\base.vcxproj" /> <ProjectReference Include="$(OpenConsoleDir)src\renderer\base\lib\base.vcxproj" />
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj" />
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj" /> <ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj" />
<ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj" /> <ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj" />
<ProjectReference Include="..\..\terminal\parser\lib\parser.vcxproj" /> <ProjectReference Include="..\..\terminal\parser\lib\parser.vcxproj" />

View file

@ -1210,9 +1210,7 @@ try
{ {
const gsl::span<COLORREF> tableView = { _colorTable.data(), _colorTable.size() }; const gsl::span<COLORREF> tableView = { _colorTable.data(), _colorTable.size() };
// First set up the basic 256 colors // First set up the basic 256 colors
Utils::Initialize256ColorTable(tableView); Utils::InitializeColorTable(tableView);
// Then use fill the first 16 values with the Campbell scheme
Utils::InitializeCampbellColorTable(tableView);
// Then make sure all the values have an alpha of 255 // Then make sure all the values have an alpha of 255
Utils::SetColorTableAlpha(tableView, 0xff); Utils::SetColorTableAlpha(tableView, 0xff);
} }

View file

@ -7,29 +7,6 @@
using namespace Microsoft::Console::VirtualTerminal; using namespace Microsoft::Console::VirtualTerminal;
using namespace Microsoft::Console::VirtualTerminal::DispatchTypes; using namespace Microsoft::Console::VirtualTerminal::DispatchTypes;
// clang-format off
const BYTE RED_ATTR = 0x01;
const BYTE GREEN_ATTR = 0x02;
const BYTE BLUE_ATTR = 0x04;
const BYTE BRIGHT_ATTR = 0x08;
const BYTE DARK_BLACK = 0;
const BYTE DARK_RED = RED_ATTR;
const BYTE DARK_GREEN = GREEN_ATTR;
const BYTE DARK_YELLOW = RED_ATTR | GREEN_ATTR;
const BYTE DARK_BLUE = BLUE_ATTR;
const BYTE DARK_MAGENTA = RED_ATTR | BLUE_ATTR;
const BYTE DARK_CYAN = GREEN_ATTR | BLUE_ATTR;
const BYTE DARK_WHITE = RED_ATTR | GREEN_ATTR | BLUE_ATTR;
const BYTE BRIGHT_BLACK = BRIGHT_ATTR;
const BYTE BRIGHT_RED = BRIGHT_ATTR | RED_ATTR;
const BYTE BRIGHT_GREEN = BRIGHT_ATTR | GREEN_ATTR;
const BYTE BRIGHT_YELLOW = BRIGHT_ATTR | RED_ATTR | GREEN_ATTR;
const BYTE BRIGHT_BLUE = BRIGHT_ATTR | BLUE_ATTR;
const BYTE BRIGHT_MAGENTA = BRIGHT_ATTR | RED_ATTR | BLUE_ATTR;
const BYTE BRIGHT_CYAN = BRIGHT_ATTR | GREEN_ATTR | BLUE_ATTR;
const BYTE BRIGHT_WHITE = BRIGHT_ATTR | RED_ATTR | GREEN_ATTR | BLUE_ATTR;
// clang-format on
// Routine Description: // Routine Description:
// - Helper to parse extended graphics options, which start with 38 (FG) or 48 (BG) // - Helper to parse extended graphics options, which start with 38 (FG) or 48 (BG)
// These options are followed by either a 2 (RGB) or 5 (xterm index) // These options are followed by either a 2 (RGB) or 5 (xterm index)
@ -169,100 +146,100 @@ bool TerminalDispatch::SetGraphicsRendition(const VTParameters options) noexcept
attr.SetOverlined(false); attr.SetOverlined(false);
break; break;
case ForegroundBlack: case ForegroundBlack:
attr.SetIndexedForeground(DARK_BLACK); attr.SetIndexedForeground(TextColor::DARK_BLACK);
break; break;
case ForegroundBlue: case ForegroundBlue:
attr.SetIndexedForeground(DARK_BLUE); attr.SetIndexedForeground(TextColor::DARK_BLUE);
break; break;
case ForegroundGreen: case ForegroundGreen:
attr.SetIndexedForeground(DARK_GREEN); attr.SetIndexedForeground(TextColor::DARK_GREEN);
break; break;
case ForegroundCyan: case ForegroundCyan:
attr.SetIndexedForeground(DARK_CYAN); attr.SetIndexedForeground(TextColor::DARK_CYAN);
break; break;
case ForegroundRed: case ForegroundRed:
attr.SetIndexedForeground(DARK_RED); attr.SetIndexedForeground(TextColor::DARK_RED);
break; break;
case ForegroundMagenta: case ForegroundMagenta:
attr.SetIndexedForeground(DARK_MAGENTA); attr.SetIndexedForeground(TextColor::DARK_MAGENTA);
break; break;
case ForegroundYellow: case ForegroundYellow:
attr.SetIndexedForeground(DARK_YELLOW); attr.SetIndexedForeground(TextColor::DARK_YELLOW);
break; break;
case ForegroundWhite: case ForegroundWhite:
attr.SetIndexedForeground(DARK_WHITE); attr.SetIndexedForeground(TextColor::DARK_WHITE);
break; break;
case BackgroundBlack: case BackgroundBlack:
attr.SetIndexedBackground(DARK_BLACK); attr.SetIndexedBackground(TextColor::DARK_BLACK);
break; break;
case BackgroundBlue: case BackgroundBlue:
attr.SetIndexedBackground(DARK_BLUE); attr.SetIndexedBackground(TextColor::DARK_BLUE);
break; break;
case BackgroundGreen: case BackgroundGreen:
attr.SetIndexedBackground(DARK_GREEN); attr.SetIndexedBackground(TextColor::DARK_GREEN);
break; break;
case BackgroundCyan: case BackgroundCyan:
attr.SetIndexedBackground(DARK_CYAN); attr.SetIndexedBackground(TextColor::DARK_CYAN);
break; break;
case BackgroundRed: case BackgroundRed:
attr.SetIndexedBackground(DARK_RED); attr.SetIndexedBackground(TextColor::DARK_RED);
break; break;
case BackgroundMagenta: case BackgroundMagenta:
attr.SetIndexedBackground(DARK_MAGENTA); attr.SetIndexedBackground(TextColor::DARK_MAGENTA);
break; break;
case BackgroundYellow: case BackgroundYellow:
attr.SetIndexedBackground(DARK_YELLOW); attr.SetIndexedBackground(TextColor::DARK_YELLOW);
break; break;
case BackgroundWhite: case BackgroundWhite:
attr.SetIndexedBackground(DARK_WHITE); attr.SetIndexedBackground(TextColor::DARK_WHITE);
break; break;
case BrightForegroundBlack: case BrightForegroundBlack:
attr.SetIndexedForeground(BRIGHT_BLACK); attr.SetIndexedForeground(TextColor::BRIGHT_BLACK);
break; break;
case BrightForegroundBlue: case BrightForegroundBlue:
attr.SetIndexedForeground(BRIGHT_BLUE); attr.SetIndexedForeground(TextColor::BRIGHT_BLUE);
break; break;
case BrightForegroundGreen: case BrightForegroundGreen:
attr.SetIndexedForeground(BRIGHT_GREEN); attr.SetIndexedForeground(TextColor::BRIGHT_GREEN);
break; break;
case BrightForegroundCyan: case BrightForegroundCyan:
attr.SetIndexedForeground(BRIGHT_CYAN); attr.SetIndexedForeground(TextColor::BRIGHT_CYAN);
break; break;
case BrightForegroundRed: case BrightForegroundRed:
attr.SetIndexedForeground(BRIGHT_RED); attr.SetIndexedForeground(TextColor::BRIGHT_RED);
break; break;
case BrightForegroundMagenta: case BrightForegroundMagenta:
attr.SetIndexedForeground(BRIGHT_MAGENTA); attr.SetIndexedForeground(TextColor::BRIGHT_MAGENTA);
break; break;
case BrightForegroundYellow: case BrightForegroundYellow:
attr.SetIndexedForeground(BRIGHT_YELLOW); attr.SetIndexedForeground(TextColor::BRIGHT_YELLOW);
break; break;
case BrightForegroundWhite: case BrightForegroundWhite:
attr.SetIndexedForeground(BRIGHT_WHITE); attr.SetIndexedForeground(TextColor::BRIGHT_WHITE);
break; break;
case BrightBackgroundBlack: case BrightBackgroundBlack:
attr.SetIndexedBackground(BRIGHT_BLACK); attr.SetIndexedBackground(TextColor::BRIGHT_BLACK);
break; break;
case BrightBackgroundBlue: case BrightBackgroundBlue:
attr.SetIndexedBackground(BRIGHT_BLUE); attr.SetIndexedBackground(TextColor::BRIGHT_BLUE);
break; break;
case BrightBackgroundGreen: case BrightBackgroundGreen:
attr.SetIndexedBackground(BRIGHT_GREEN); attr.SetIndexedBackground(TextColor::BRIGHT_GREEN);
break; break;
case BrightBackgroundCyan: case BrightBackgroundCyan:
attr.SetIndexedBackground(BRIGHT_CYAN); attr.SetIndexedBackground(TextColor::BRIGHT_CYAN);
break; break;
case BrightBackgroundRed: case BrightBackgroundRed:
attr.SetIndexedBackground(BRIGHT_RED); attr.SetIndexedBackground(TextColor::BRIGHT_RED);
break; break;
case BrightBackgroundMagenta: case BrightBackgroundMagenta:
attr.SetIndexedBackground(BRIGHT_MAGENTA); attr.SetIndexedBackground(TextColor::BRIGHT_MAGENTA);
break; break;
case BrightBackgroundYellow: case BrightBackgroundYellow:
attr.SetIndexedBackground(BRIGHT_YELLOW); attr.SetIndexedBackground(TextColor::BRIGHT_YELLOW);
break; break;
case BrightBackgroundWhite: case BrightBackgroundWhite:
attr.SetIndexedBackground(BRIGHT_WHITE); attr.SetIndexedBackground(TextColor::BRIGHT_WHITE);
break; break;
case ForegroundExtended: case ForegroundExtended:
i += _SetRgbColorsHelper(options.subspan(i + 1), attr, true); i += _SetRgbColorsHelper(options.subspan(i + 1), attr, true);

View file

@ -37,6 +37,9 @@
<ProjectReference Include="$(OpenConsoleDir)src\terminal\parser\lib\parser.vcxproj"> <ProjectReference Include="$(OpenConsoleDir)src\terminal\parser\lib\parser.vcxproj">
<Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project> <Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\renderer\dx\lib\dx.vcxproj"> <ProjectReference Include="$(OpenConsoleDir)src\renderer\dx\lib\dx.vcxproj">
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project> <Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
</ProjectReference> </ProjectReference>

View file

@ -246,13 +246,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return _profile.HasUnfocusedAppearance(); return _profile.HasUnfocusedAppearance();
} }
bool ProfileViewModel::EditableUnfocusedAppearance() bool ProfileViewModel::EditableUnfocusedAppearance() const noexcept
{ {
if constexpr (Feature_EditableUnfocusedAppearance::IsEnabled()) return Feature_EditableUnfocusedAppearance::IsEnabled();
{
return true;
}
return false;
} }
bool ProfileViewModel::ShowUnfocusedAppearance() bool ProfileViewModel::ShowUnfocusedAppearance()
@ -286,6 +282,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return _unfocusedAppearanceViewModel; return _unfocusedAppearanceViewModel;
} }
bool ProfileViewModel::AtlasEngineAvailable() const noexcept
{
return Feature_AtlasEngine::IsEnabled();
}
bool ProfileViewModel::UseParentProcessDirectory() bool ProfileViewModel::UseParentProcessDirectory()
{ {
return StartingDirectory().empty(); return StartingDirectory().empty();

View file

@ -61,12 +61,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Editor::AppearanceViewModel DefaultAppearance(); Editor::AppearanceViewModel DefaultAppearance();
Editor::AppearanceViewModel UnfocusedAppearance(); Editor::AppearanceViewModel UnfocusedAppearance();
bool HasUnfocusedAppearance(); bool HasUnfocusedAppearance();
bool EditableUnfocusedAppearance(); bool EditableUnfocusedAppearance() const noexcept;
bool ShowUnfocusedAppearance(); bool ShowUnfocusedAppearance();
void CreateUnfocusedAppearance(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& schemes, void CreateUnfocusedAppearance(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& schemes,
const IHostedInWindow& windowRoot); const IHostedInWindow& windowRoot);
void DeleteUnfocusedAppearance(); void DeleteUnfocusedAppearance();
bool AtlasEngineAvailable() const noexcept;
WINRT_PROPERTY(bool, IsBaseLayer, false); WINRT_PROPERTY(bool, IsBaseLayer, false);
@ -86,8 +86,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, Commandline); OBSERVABLE_PROJECTED_SETTING(_profile, Commandline);
OBSERVABLE_PROJECTED_SETTING(_profile, StartingDirectory); OBSERVABLE_PROJECTED_SETTING(_profile, StartingDirectory);
OBSERVABLE_PROJECTED_SETTING(_profile, AntialiasingMode); OBSERVABLE_PROJECTED_SETTING(_profile, AntialiasingMode);
OBSERVABLE_PROJECTED_SETTING(_profile, ForceFullRepaintRendering);
OBSERVABLE_PROJECTED_SETTING(_profile, SoftwareRendering);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Foreground); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Foreground);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), Background);
OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground); OBSERVABLE_PROJECTED_SETTING(_profile.DefaultAppearance(), SelectionBackground);
@ -97,6 +95,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput); OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput);
OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing); OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing);
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle); OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
OBSERVABLE_PROJECTED_SETTING(_profile, UseAtlasEngine);
private: private:
Model::Profile _profile; Model::Profile _profile;

View file

@ -32,6 +32,7 @@ namespace Microsoft.Terminal.Settings.Editor
Boolean EditableUnfocusedAppearance { get; }; Boolean EditableUnfocusedAppearance { get; };
Boolean ShowUnfocusedAppearance { get; }; Boolean ShowUnfocusedAppearance { get; };
AppearanceViewModel UnfocusedAppearance { get; }; AppearanceViewModel UnfocusedAppearance { get; };
Boolean AtlasEngineAvailable { get; };
void CreateUnfocusedAppearance(Windows.Foundation.Collections.IMapView<String, Microsoft.Terminal.Settings.Model.ColorScheme> Schemes, IHostedInWindow WindowRoot); void CreateUnfocusedAppearance(Windows.Foundation.Collections.IMapView<String, Microsoft.Terminal.Settings.Model.ColorScheme> Schemes, IHostedInWindow WindowRoot);
void DeleteUnfocusedAppearance(); void DeleteUnfocusedAppearance();
@ -53,8 +54,6 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline); OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline);
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, StartingDirectory); OBSERVABLE_PROJECTED_PROFILE_SETTING(String, StartingDirectory);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.TextAntialiasingMode, AntialiasingMode); OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.TextAntialiasingMode, AntialiasingMode);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, ForceFullRepaintRendering);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SoftwareRendering);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, Foreground); OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, Foreground);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, Background); OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, Background);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, SelectionBackground); OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.IReference<Microsoft.Terminal.Core.Color>, SelectionBackground);
@ -63,6 +62,7 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SnapOnInput); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SnapOnInput);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing); OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle); OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAtlasEngine);
} }
runtimeclass DeleteProfileEventArgs runtimeclass DeleteProfileEventArgs

View file

@ -319,7 +319,7 @@
</StackPanel> </StackPanel>
<StackPanel> <StackPanel>
<StackPanel Orientation="Horizontal" <StackPanel Orientation="Horizontal"
Visibility="{x:Bind State.Profile.EditableUnfocusedAppearance, Mode=OneWay}"> Visibility="{x:Bind State.Profile.EditableUnfocusedAppearance}">
<TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock" <TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock"
Style="{StaticResource TitleTextBlockStyle}" /> Style="{StaticResource TitleTextBlockStyle}" />
<Button x:Uid="Profile_CreateUnfocusedAppearanceButton" <Button x:Uid="Profile_CreateUnfocusedAppearanceButton"
@ -477,6 +477,15 @@
IsChecked="{x:Bind IsBellStyleFlagSet(4), BindBack=SetBellStyleTaskbar, Mode=TwoWay}" /> IsChecked="{x:Bind IsBellStyleFlagSet(4), BindBack=SetBellStyleTaskbar, Mode=TwoWay}" />
</StackPanel> </StackPanel>
</local:SettingContainer> </local:SettingContainer>
<!-- AtlasEngine -->
<local:SettingContainer x:Uid="Profile_UseAtlasEngine"
ClearSettingValue="{x:Bind State.Profile.ClearUseAtlasEngine}"
HasSettingValue="{x:Bind State.Profile.HasUseAtlasEngine, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.UseAtlasEngineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind State.Profile.AtlasEngineAvailable}">
<ToggleSwitch IsOn="{x:Bind State.Profile.UseAtlasEngine, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
</PivotItem> </PivotItem>

View file

@ -927,6 +927,10 @@
<value>Controls what happens when the application emits a BEL character.</value> <value>Controls what happens when the application emits a BEL character.</value>
<comment>A description for what the "bell style" setting does. Presented near "Profile_BellStyle".{Locked="BEL"}</comment> <comment>A description for what the "bell style" setting does. Presented near "Profile_BellStyle".{Locked="BEL"}</comment>
</data> </data>
<data name="Profile_UseAtlasEngine.Header" xml:space="preserve">
<value>Enable experimental text rendering engine</value>
<comment>An option to enable an experimental text rendering engine</comment>
</data>
<data name="Profile_BellStyleAudible.Content" xml:space="preserve"> <data name="Profile_BellStyleAudible.Content" xml:space="preserve">
<value>Audible</value> <value>Audible</value>
<comment>An option to choose from for the "bell style" setting. When selected, an audible cue is used to notify the user.</comment> <comment>An option to choose from for the "bell style" setting. When selected, an audible cue is used to notify the user.</comment>

View file

@ -16,17 +16,6 @@ static constexpr std::string_view ForegroundKey{ "foreground" };
static constexpr std::string_view BackgroundKey{ "background" }; static constexpr std::string_view BackgroundKey{ "background" };
static constexpr std::string_view SelectionBackgroundKey{ "selectionBackground" }; static constexpr std::string_view SelectionBackgroundKey{ "selectionBackground" };
static constexpr std::string_view CursorColorKey{ "cursorColor" }; static constexpr std::string_view CursorColorKey{ "cursorColor" };
static constexpr std::string_view CursorShapeKey{ "cursorShape" };
static constexpr std::string_view CursorHeightKey{ "cursorHeight" };
static constexpr std::string_view BackgroundImageKey{ "backgroundImage" };
static constexpr std::string_view ColorSchemeKey{ "colorScheme" };
static constexpr std::string_view BackgroundImageOpacityKey{ "backgroundImageOpacity" };
static constexpr std::string_view BackgroundImageStretchModeKey{ "backgroundImageStretchMode" };
static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageAlignment" };
static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" };
static constexpr std::string_view PixelShaderPathKey{ "experimental.pixelShaderPath" };
static constexpr std::string_view IntenseTextStyleKey{ "intenseTextStyle" };
static constexpr std::string_view AdjustIndistinguishableColorsKey{ "adjustIndistinguishableColors" };
static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" }; static constexpr std::string_view LegacyAcrylicTransparencyKey{ "acrylicOpacity" };
static constexpr std::string_view OpacityKey{ "opacity" }; static constexpr std::string_view OpacityKey{ "opacity" };
@ -38,22 +27,17 @@ AppearanceConfig::AppearanceConfig(winrt::weak_ref<Profile> sourceProfile) :
winrt::com_ptr<AppearanceConfig> AppearanceConfig::CopyAppearance(const AppearanceConfig* source, winrt::weak_ref<Profile> sourceProfile) winrt::com_ptr<AppearanceConfig> AppearanceConfig::CopyAppearance(const AppearanceConfig* source, winrt::weak_ref<Profile> sourceProfile)
{ {
auto appearance{ winrt::make_self<AppearanceConfig>(std::move(sourceProfile)) }; auto appearance{ winrt::make_self<AppearanceConfig>(std::move(sourceProfile)) };
appearance->_BackgroundImagePath = source->_BackgroundImagePath;
appearance->_BackgroundImageOpacity = source->_BackgroundImageOpacity;
appearance->_BackgroundImageStretchMode = source->_BackgroundImageStretchMode;
appearance->_ColorSchemeName = source->_ColorSchemeName;
appearance->_Foreground = source->_Foreground; appearance->_Foreground = source->_Foreground;
appearance->_Background = source->_Background; appearance->_Background = source->_Background;
appearance->_SelectionBackground = source->_SelectionBackground; appearance->_SelectionBackground = source->_SelectionBackground;
appearance->_CursorColor = source->_CursorColor; appearance->_CursorColor = source->_CursorColor;
appearance->_CursorShape = source->_CursorShape;
appearance->_CursorHeight = source->_CursorHeight;
appearance->_BackgroundImageAlignment = source->_BackgroundImageAlignment;
appearance->_RetroTerminalEffect = source->_RetroTerminalEffect;
appearance->_PixelShaderPath = source->_PixelShaderPath;
appearance->_IntenseTextStyle = source->_IntenseTextStyle;
appearance->_Opacity = source->_Opacity; appearance->_Opacity = source->_Opacity;
appearance->_AdjustIndistinguishableColors = source->_AdjustIndistinguishableColors;
#define APPEARANCE_SETTINGS_COPY(type, name, jsonKey, ...) \
appearance->_##name = source->_##name;
MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_COPY)
#undef APPEARANCE_SETTINGS_COPY
return appearance; return appearance;
} }
@ -65,19 +49,13 @@ Json::Value AppearanceConfig::ToJson() const
JsonUtils::SetValueForKey(json, BackgroundKey, _Background); JsonUtils::SetValueForKey(json, BackgroundKey, _Background);
JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground); JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::SetValueForKey(json, CursorColorKey, _CursorColor); JsonUtils::SetValueForKey(json, CursorColorKey, _CursorColor);
JsonUtils::SetValueForKey(json, ColorSchemeKey, _ColorSchemeName);
JsonUtils::SetValueForKey(json, CursorHeightKey, _CursorHeight);
JsonUtils::SetValueForKey(json, CursorShapeKey, _CursorShape);
JsonUtils::SetValueForKey(json, BackgroundImageKey, _BackgroundImagePath);
JsonUtils::SetValueForKey(json, BackgroundImageOpacityKey, _BackgroundImageOpacity);
JsonUtils::SetValueForKey(json, BackgroundImageStretchModeKey, _BackgroundImageStretchMode);
JsonUtils::SetValueForKey(json, BackgroundImageAlignmentKey, _BackgroundImageAlignment);
JsonUtils::SetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
JsonUtils::SetValueForKey(json, PixelShaderPathKey, _PixelShaderPath);
JsonUtils::SetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle);
JsonUtils::SetValueForKey(json, AdjustIndistinguishableColorsKey, _AdjustIndistinguishableColors);
JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<double, IntAsFloatPercentConversionTrait>{}); JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<double, IntAsFloatPercentConversionTrait>{});
#define APPEARANCE_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
JsonUtils::SetValueForKey(json, jsonKey, _##name);
MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_TO_JSON)
#undef APPEARANCE_SETTINGS_TO_JSON
return json; return json;
} }
@ -98,19 +76,14 @@ void AppearanceConfig::LayerJson(const Json::Value& json)
JsonUtils::GetValueForKey(json, BackgroundKey, _Background); JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground); JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor); JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);
JsonUtils::GetValueForKey(json, CursorHeightKey, _CursorHeight);
JsonUtils::GetValueForKey(json, ColorSchemeKey, _ColorSchemeName);
JsonUtils::GetValueForKey(json, CursorShapeKey, _CursorShape);
JsonUtils::GetValueForKey(json, BackgroundImageKey, _BackgroundImagePath);
JsonUtils::GetValueForKey(json, BackgroundImageOpacityKey, _BackgroundImageOpacity);
JsonUtils::GetValueForKey(json, BackgroundImageStretchModeKey, _BackgroundImageStretchMode);
JsonUtils::GetValueForKey(json, BackgroundImageAlignmentKey, _BackgroundImageAlignment);
JsonUtils::GetValueForKey(json, RetroTerminalEffectKey, _RetroTerminalEffect);
JsonUtils::GetValueForKey(json, PixelShaderPathKey, _PixelShaderPath);
JsonUtils::GetValueForKey(json, IntenseTextStyleKey, _IntenseTextStyle);
JsonUtils::GetValueForKey(json, AdjustIndistinguishableColorsKey, _AdjustIndistinguishableColors);
JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity); JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity);
JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<double, IntAsFloatPercentConversionTrait>{}); JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<double, IntAsFloatPercentConversionTrait>{});
#define APPEARANCE_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
JsonUtils::GetValueForKey(json, jsonKey, _##name);
MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_LAYER_JSON)
#undef APPEARANCE_SETTINGS_LAYER_JSON
} }
winrt::Microsoft::Terminal::Settings::Model::Profile AppearanceConfig::SourceProfile() winrt::Microsoft::Terminal::Settings::Model::Profile AppearanceConfig::SourceProfile()

View file

@ -19,6 +19,7 @@ Author(s):
#include "AppearanceConfig.g.h" #include "AppearanceConfig.g.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "IInheritable.h" #include "IInheritable.h"
#include "MTSMSettings.h"
#include <DefaultSettings.h> #include <DefaultSettings.h>
namespace winrt::Microsoft::Terminal::Settings::Model::implementation namespace winrt::Microsoft::Terminal::Settings::Model::implementation
@ -35,26 +36,16 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
winrt::hstring ExpandedBackgroundImagePath(); winrt::hstring ExpandedBackgroundImagePath();
INHERITABLE_SETTING(Model::IAppearanceConfig, ConvergedAlignment, BackgroundImageAlignment, ConvergedAlignment::Horizontal_Center | ConvergedAlignment::Vertical_Center);
INHERITABLE_SETTING(Model::IAppearanceConfig, uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, ColorSchemeName, L"Campbell");
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, Foreground, nullptr); INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, Foreground, nullptr);
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, Background, nullptr); INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, Background, nullptr);
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, SelectionBackground, nullptr); INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, SelectionBackground, nullptr);
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, CursorColor, nullptr); INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, CursorColor, nullptr);
INHERITABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::CursorStyle, CursorShape, Microsoft::Terminal::Core::CursorStyle::Bar);
INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, BackgroundImagePath);
INHERITABLE_SETTING(Model::IAppearanceConfig, double, BackgroundImageOpacity, 1.0);
INHERITABLE_SETTING(Model::IAppearanceConfig, Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, Windows::UI::Xaml::Media::Stretch::UniformToFill);
INHERITABLE_SETTING(Model::IAppearanceConfig, bool, RetroTerminalEffect, false);
INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, PixelShaderPath, L"");
INHERITABLE_SETTING(Model::IAppearanceConfig, Model::IntenseStyle, IntenseTextStyle, Model::IntenseStyle::Bright);
INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0); INHERITABLE_SETTING(Model::IAppearanceConfig, double, Opacity, 1.0);
INHERITABLE_SETTING(Model::IAppearanceConfig, bool, AdjustIndistinguishableColors, true); #define APPEARANCE_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
INHERITABLE_SETTING(Model::IAppearanceConfig, type, name, ##__VA_ARGS__)
MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_INITIALIZE)
#undef APPEARANCE_SETTINGS_INITIALIZE
private: private:
winrt::weak_ref<Profile> _sourceProfile; winrt::weak_ref<Profile> _sourceProfile;

View file

@ -9,8 +9,11 @@
#include "ActionAndArgs.h" #include "ActionAndArgs.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "FileUtils.h" #include "FileUtils.h"
#include "../../types/inc/utils.hpp"
static constexpr std::wstring_view stateFileName{ L"state.json" }; static constexpr std::wstring_view stateFileName{ L"state.json" };
static constexpr std::wstring_view elevatedStateFileName{ L"elevated-state.json" };
static constexpr std::string_view TabLayoutKey{ "tabLayout" }; static constexpr std::string_view TabLayoutKey{ "tabLayout" };
static constexpr std::string_view InitialPositionKey{ "initialPosition" }; static constexpr std::string_view InitialPositionKey{ "initialPosition" };
static constexpr std::string_view InitialSizeKey{ "initialSize" }; static constexpr std::string_view InitialSizeKey{ "initialSize" };
@ -85,15 +88,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return trait.FromJson(root); return trait.FromJson(root);
} }
// Returns the application-global ApplicationState object. ApplicationState::ApplicationState(const std::filesystem::path& stateRoot) noexcept :
Microsoft::Terminal::Settings::Model::ApplicationState ApplicationState::SharedInstance() _sharedPath{ stateRoot / stateFileName },
{ _elevatedPath{ stateRoot / elevatedStateFileName },
static auto state = winrt::make_self<ApplicationState>(GetBaseSettingsPath() / stateFileName);
return *state;
}
ApplicationState::ApplicationState(std::filesystem::path path) noexcept :
_path{ std::move(path) },
_throttler{ std::chrono::seconds(1), [this]() { _write(); } } _throttler{ std::chrono::seconds(1), [this]() { _write(); } }
{ {
_read(); _read();
@ -102,9 +99,21 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// The destructor ensures that the last write is flushed to disk before returning. // The destructor ensures that the last write is flushed to disk before returning.
ApplicationState::~ApplicationState() ApplicationState::~ApplicationState()
{ {
TraceLoggingWrite(g_hSettingsModelProvider,
"ApplicationState_Dtor_Start",
TraceLoggingDescription("Event at the start of the ApplicationState destructor"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
// This will ensure that we not just cancel the last outstanding timer, // This will ensure that we not just cancel the last outstanding timer,
// but instead force it to run as soon as possible and wait for it to complete. // but instead force it to run as soon as possible and wait for it to complete.
_throttler.flush(); _throttler.flush();
TraceLoggingWrite(g_hSettingsModelProvider,
"ApplicationState_Dtor_End",
TraceLoggingDescription("Event at the end of the ApplicationState destructor"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
} }
// Re-read the state.json from disk. // Re-read the state.json from disk.
@ -113,34 +122,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_read(); _read();
} }
// Returns the state.json path on the disk. bool ApplicationState::IsStatePath(const winrt::hstring& filename)
winrt::hstring ApplicationState::FilePath() const noexcept
{ {
return winrt::hstring{ _path.wstring() }; static const auto sharedPath{ _sharedPath.filename() };
static const auto elevatedPath{ _elevatedPath.filename() };
return filename == sharedPath || filename == elevatedPath;
} }
// Generate all getter/setters
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
type ApplicationState::name() const noexcept \
{ \
const auto state = _state.lock_shared(); \
const auto& value = state->name; \
return value ? *value : type{ __VA_ARGS__ }; \
} \
\
void ApplicationState::name(const type& value) noexcept \
{ \
{ \
auto state = _state.lock(); \
state->name.emplace(value); \
state->name##Changed = true; \
} \
\
_throttler(); \
}
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
// Method Description: // Method Description:
// - See GH#11119. Removes all of the data in this ApplicationState object // - See GH#11119. Removes all of the data in this ApplicationState object
// and resets it to the defaults. This will delete the state file! That's // and resets it to the defaults. This will delete the state file! That's
@ -156,57 +144,58 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void ApplicationState::Reset() noexcept void ApplicationState::Reset() noexcept
try try
{ {
LOG_LAST_ERROR_IF(!DeleteFile(_path.c_str())); LOG_LAST_ERROR_IF(!DeleteFile(_sharedPath.c_str()));
LOG_LAST_ERROR_IF(!DeleteFile(_elevatedPath.c_str()));
*_state.lock() = {}; *_state.lock() = {};
} }
CATCH_LOG() CATCH_LOG()
Json::Value ApplicationState::_getRoot(const locked_hfile& file) const noexcept // Deserializes the state.json and user-state (or elevated-state if
{ // elevated) into this ApplicationState.
Json::Value root;
try
{
const auto data = ReadUTF8FileLocked(file);
if (data.empty())
{
return root;
}
std::string errs;
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
if (!reader->parse(data.data(), data.data() + data.size(), &root, &errs))
{
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
}
}
CATCH_LOG()
return root;
}
// Deserializes the state.json at _path into this ApplicationState.
// * ANY errors during app state will result in the creation of a new empty state. // * ANY errors during app state will result in the creation of a new empty state.
// * ANY errors during runtime will result in changes being partially ignored. // * ANY errors during runtime will result in changes being partially ignored.
void ApplicationState::_read() const noexcept void ApplicationState::_read() const noexcept
try try
{ {
auto state = _state.lock(); std::string errs;
const auto file = OpenFileReadSharedLocked(_path); std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
auto root = _getRoot(file); // First get shared state out of `state.json`.
// GetValueForKey() comes in two variants: const auto sharedData = _readSharedContents().value_or(std::string{});
// * take a std::optional<T> reference if (!sharedData.empty())
// * return std::optional<T> by value {
// At the time of writing the former version skips missing fields in the json, Json::Value root;
// but we want to explicitly clear state fields that were removed from state.json. if (!reader->parse(sharedData.data(), sharedData.data() + sharedData.size(), &root, &errs))
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \ {
if (!state->name##Changed) \ throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
{ \ }
state->name = JsonUtils::GetValueForKey<std::optional<type>>(root, key); \
} // - If we're elevated, we want to only load the Shared properties
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN) // from state.json. We'll then load the Local props from
#undef MTSM_APPLICATION_STATE_GEN // `elevated-state.json`
// - If we're unelevated, then load _everything_ from state.json.
if (::Microsoft::Console::Utils::IsElevated())
{
// Only load shared properties if we're elevated
FromJson(root, FileSource::Shared);
// Then, try and get anything in elevated-state
if (const auto localData{ _readLocalContents().value_or(std::string{}) }; !localData.empty())
{
Json::Value root;
if (!reader->parse(localData.data(), localData.data() + localData.size(), &root, &errs))
{
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
}
FromJson(root, FileSource::Local);
}
}
else
{
// If we're unelevated, then load everything.
FromJson(root, FileSource::Shared | FileSource::Local);
}
}
} }
CATCH_LOG() CATCH_LOG()
@ -214,29 +203,191 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// * Errors are only logged. // * Errors are only logged.
// * _state->_writeScheduled is set to false, signaling our // * _state->_writeScheduled is set to false, signaling our
// setters that _synchronize() needs to be called again. // setters that _synchronize() needs to be called again.
void ApplicationState::_write() noexcept void ApplicationState::_write() const noexcept
try try
{ {
// re-read the state so that we can only update the properties that were changed. Json::StreamWriterBuilder wbuilder;
Json::Value root{};
// When we're elevated, we've got to be tricky. We don't want to write
// our window state, allowed commandlines, and other Local properties
// into the shared `state.json`. But, if we only serialize the Shared
// properties to a json blob, then we'll omit windowState entirely,
// _removing_ the window state of the unelevated instance. Oh no!
//
// So, to be tricky, we'll first _load_ the shared state to a json blob.
// We'll then serialize our view of the shared properties on top of that
// blob. Then we'll write that blob back to the file. This will
// round-trip the Local properties for the unelevated instances
// untouched in state.json
//
// After that's done, we'll write our Local properties into
// elevated-state.json.
if (::Microsoft::Console::Utils::IsElevated())
{ {
auto state = _state.lock(); std::string errs;
const auto file = OpenFileRWExclusiveLocked(_path); std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
root = _getRoot(file); Json::Value root;
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \ // First load the contents of state.json into a json blob. This will
if (state->name##Changed) \ // contain the Shared properties and the unelevated instance's Local
{ \ // properties.
JsonUtils::SetValueForKey(root, key, state->name); \ const auto sharedData = _readSharedContents().value_or(std::string{});
state->name##Changed = false; \ if (!sharedData.empty())
} {
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN) if (!reader->parse(sharedData.data(), sharedData.data() + sharedData.size(), &root, &errs))
#undef MTSM_APPLICATION_STATE_GEN {
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
}
}
// Layer our shared properties on top of the blob from state.json,
// and write it back out.
_writeSharedContents(Json::writeString(wbuilder, _toJsonWithBlob(root, FileSource::Shared)));
Json::StreamWriterBuilder wbuilder; // Finally, write our Local properties back to elevated-state.json
const auto content = Json::writeString(wbuilder, root); _writeLocalContents(Json::writeString(wbuilder, ToJson(FileSource::Local)));
WriteUTF8FileLocked(file, content); }
else
{
// We're unelevated, this is easy. Just write everything back out.
_writeLocalContents(Json::writeString(wbuilder, ToJson(FileSource::Local | FileSource::Shared)));
} }
} }
CATCH_LOG() CATCH_LOG()
// Returns the application-global ApplicationState object.
Microsoft::Terminal::Settings::Model::ApplicationState ApplicationState::SharedInstance()
{
std::filesystem::path root{ GetBaseSettingsPath() };
static auto state = winrt::make_self<ApplicationState>(root);
return *state;
}
// Method Description:
// - Loads data from the given json blob. Will only read the data that's in
// the specified parseSource - so if we're reading the Local state file,
// we won't destroy previously parsed Shared data.
// - READ: there's no layering for app state.
void ApplicationState::FromJson(const Json::Value& root, FileSource parseSource) const noexcept
{
auto state = _state.lock();
// GetValueForKey() comes in two variants:
// * take a std::optional<T> reference
// * return std::optional<T> by value
// At the time of writing the former version skips missing fields in the json,
// but we want to explicitly clear state fields that were removed from state.json.
//
// GH#11222: We only load properties that are of the same type (Local or
// Shared) which we requested. If we didn't want to load this type of
// property, just skip it.
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
if (WI_IsFlagSet(parseSource, source)) \
state->name = JsonUtils::GetValueForKey<std::optional<type>>(root, key);
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
}
Json::Value ApplicationState::ToJson(FileSource parseSource) const noexcept
{
Json::Value root{ Json::objectValue };
return _toJsonWithBlob(root, parseSource);
}
Json::Value ApplicationState::_toJsonWithBlob(Json::Value& root, FileSource parseSource) const noexcept
{
{
auto state = _state.lock_shared();
// GH#11222: We only write properties that are of the same type (Local
// or Shared) which we requested. If we didn't want to serialize this
// type of property, just skip it.
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
if (WI_IsFlagSet(parseSource, source)) \
JsonUtils::SetValueForKey(root, key, state->name);
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
}
return root;
}
// Generate all getter/setters
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
type ApplicationState::name() const noexcept \
{ \
const auto state = _state.lock_shared(); \
const auto& value = state->name; \
return value ? *value : type{ __VA_ARGS__ }; \
} \
\
void ApplicationState::name(const type& value) noexcept \
{ \
{ \
auto state = _state.lock(); \
state->name.emplace(value); \
} \
\
_throttler(); \
}
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN
// Method Description:
// - Read the contents of our "shared" state - state that should be shared
// for elevated and unelevated instances. This is things like the list of
// generated profiles, the command palette commandlines.
std::optional<std::string> ApplicationState::_readSharedContents() const
{
return ReadUTF8FileIfExists(_sharedPath);
}
// Method Description:
// - Read the contents of our "local" state - state that should be kept in
// separate files for elevated and unelevated instances. This is things
// like the persisted window state, and the approved commandlines (though,
// those don't matter when unelevated).
// - When elevated, this will DELETE `elevated-state.json` if it has bad
// permissions, so we don't potentially read malicious data.
std::optional<std::string> ApplicationState::_readLocalContents() const
{
return ::Microsoft::Console::Utils::IsElevated() ?
ReadUTF8FileIfExists(_elevatedPath, true) :
ReadUTF8FileIfExists(_sharedPath, false);
}
// Method Description:
// - Write the contents of our "shared" state - state that should be shared
// for elevated and unelevated instances. This will atomically write to
// `state.json`
void ApplicationState::_writeSharedContents(const std::string_view content) const
{
WriteUTF8FileAtomic(_sharedPath, content);
}
// Method Description:
// - Write the contents of our "local" state - state that should be kept in
// separate files for elevated and unelevated instances. When elevated,
// this will write to `elevated-state.json`, and when unelevated, this
// will atomically write to `user-state.json`
void ApplicationState::_writeLocalContents(const std::string_view content) const
{
if (::Microsoft::Console::Utils::IsElevated())
{
// DON'T use WriteUTF8FileAtomic, which will write to a temporary file
// then rename that file to the final filename. That actually lets us
// overwrite the elevate file's contents even when unelevated, because
// we're effectively deleting the original file, then renaming a
// different file in it's place.
//
// We're not worried about someone else doing that though, if they do
// that with the wrong permissions, then we'll just ignore the file and
// start over.
WriteUTF8File(_elevatedPath, content, true);
}
else
{
WriteUTF8FileAtomic(_sharedPath, content);
}
}
} }

View file

@ -16,21 +16,30 @@ Abstract:
#include "WindowLayout.g.h" #include "WindowLayout.g.h"
#include <inc/cppwinrt_utils.h> #include <inc/cppwinrt_utils.h>
#include <til/mutex.h>
#include <til/throttled_func.h>
#include "FileUtils.h"
#include <JsonUtils.h> #include <JsonUtils.h>
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
// If a property is Shared, then it'll be stored in `state.json`, and used
// in both elevated and unelevated instances of the Terminal. If a property
// is marked Local, then it will have separate values for elevated and
// unelevated instances.
enum FileSource : int
{
Shared = 0x1,
Local = 0x2
};
DEFINE_ENUM_FLAG_OPERATORS(FileSource);
// This macro generates all getters and setters for ApplicationState. // This macro generates all getters and setters for ApplicationState.
// It provides X with the following arguments: // It provides X with the following arguments:
// (type, function name, JSON key, ...variadic construction arguments) // (source, type, function name, JSON key, ...variadic construction arguments)
namespace winrt::Microsoft::Terminal::Settings::Model::implementation #define MTSM_APPLICATION_STATE_FIELDS(X) \
{ X(FileSource::Shared, std::unordered_set<winrt::guid>, GeneratedProfiles, "generatedProfiles") \
#define MTSM_APPLICATION_STATE_FIELDS(X) \ X(FileSource::Local, Windows::Foundation::Collections::IVector<Model::WindowLayout>, PersistedWindowLayouts, "persistedWindowLayouts") \
X(std::unordered_set<winrt::guid>, GeneratedProfiles, "generatedProfiles") \ X(FileSource::Shared, Windows::Foundation::Collections::IVector<hstring>, RecentCommands, "recentCommands") \
X(Windows::Foundation::Collections::IVector<Model::WindowLayout>, PersistedWindowLayouts, "persistedWindowLayouts") \ X(FileSource::Shared, Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage>, DismissedMessages, "dismissedMessages") \
X(Windows::Foundation::Collections::IVector<hstring>, RecentCommands, "recentCommands") \ X(FileSource::Local, Windows::Foundation::Collections::IVector<hstring>, AllowedCommandlines, "allowedCommandlines")
X(Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage>, DismissedMessages, "dismissedMessages")
struct WindowLayout : WindowLayoutT<WindowLayout> struct WindowLayout : WindowLayoutT<WindowLayout>
{ {
@ -44,23 +53,26 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
friend ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<Model::WindowLayout>; friend ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<Model::WindowLayout>;
}; };
struct ApplicationState : ApplicationStateT<ApplicationState> struct ApplicationState : public ApplicationStateT<ApplicationState>
{ {
static Microsoft::Terminal::Settings::Model::ApplicationState SharedInstance(); static Microsoft::Terminal::Settings::Model::ApplicationState SharedInstance();
ApplicationState(std::filesystem::path path) noexcept; ApplicationState(const std::filesystem::path& stateRoot) noexcept;
~ApplicationState(); ~ApplicationState();
// Methods // Methods
void Reload() const noexcept; void Reload() const noexcept;
void Reset() noexcept; void Reset() noexcept;
void FromJson(const Json::Value& root, FileSource parseSource) const noexcept;
Json::Value ToJson(FileSource parseSource) const noexcept;
// General getters/setters // General getters/setters
winrt::hstring FilePath() const noexcept; bool IsStatePath(const winrt::hstring& filename);
// State getters/setters // State getters/setters
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \ #define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
type name() const noexcept; \ type name() const noexcept; \
void name(const type& value) noexcept; void name(const type& value) noexcept;
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN) MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN #undef MTSM_APPLICATION_STATE_GEN
@ -68,21 +80,24 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
private: private:
struct state_t struct state_t
{ {
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \ #define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) std::optional<type> name{ __VA_ARGS__ };
std::optional<type> name{ __VA_ARGS__ }; \
bool name##Changed = false;
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN) MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
#undef MTSM_APPLICATION_STATE_GEN #undef MTSM_APPLICATION_STATE_GEN
}; };
til::shared_mutex<state_t> _state;
std::filesystem::path _sharedPath;
std::filesystem::path _elevatedPath;
til::throttled_func_trailing<> _throttler;
Json::Value _getRoot(const winrt::Microsoft::Terminal::Settings::Model::locked_hfile& file) const noexcept; void _write() const noexcept;
void _write() noexcept;
void _read() const noexcept; void _read() const noexcept;
std::filesystem::path _path; Json::Value _toJsonWithBlob(Json::Value& root, FileSource parseSource) const noexcept;
til::shared_mutex<state_t> _state;
til::throttled_func_trailing<> _throttler; std::optional<std::string> _readSharedContents() const;
void _writeSharedContents(const std::string_view content) const;
std::optional<std::string> _readLocalContents() const;
void _writeLocalContents(const std::string_view content) const;
}; };
} }

View file

@ -30,12 +30,15 @@ namespace Microsoft.Terminal.Settings.Model
void Reload(); void Reload();
void Reset(); void Reset();
String FilePath { get; }; Boolean IsStatePath(String filename);
Windows.Foundation.Collections.IVector<WindowLayout> PersistedWindowLayouts { get; set; }; Windows.Foundation.Collections.IVector<WindowLayout> PersistedWindowLayouts { get; set; };
Windows.Foundation.Collections.IVector<String> RecentCommands { get; set; }; Windows.Foundation.Collections.IVector<String> RecentCommands { get; set; };
Windows.Foundation.Collections.IVector<InfoBarMessage> DismissedMessages { get; set; }; Windows.Foundation.Collections.IVector<InfoBarMessage> DismissedMessages { get; set; };
Windows.Foundation.Collections.IVector<String> AllowedCommandlines { get; set; };
} }
} }

View file

@ -287,8 +287,6 @@ Model::Profile CascadiaSettings::DuplicateProfile(const Model::Profile& source)
DUPLICATE_SETTING_MACRO(Commandline); DUPLICATE_SETTING_MACRO(Commandline);
DUPLICATE_SETTING_MACRO(StartingDirectory); DUPLICATE_SETTING_MACRO(StartingDirectory);
DUPLICATE_SETTING_MACRO(AntialiasingMode); DUPLICATE_SETTING_MACRO(AntialiasingMode);
DUPLICATE_SETTING_MACRO(ForceFullRepaintRendering);
DUPLICATE_SETTING_MACRO(SoftwareRendering);
DUPLICATE_SETTING_MACRO(HistorySize); DUPLICATE_SETTING_MACRO(HistorySize);
DUPLICATE_SETTING_MACRO(SnapOnInput); DUPLICATE_SETTING_MACRO(SnapOnInput);
DUPLICATE_SETTING_MACRO(AltGrAliasing); DUPLICATE_SETTING_MACRO(AltGrAliasing);

View file

@ -8,6 +8,10 @@
#include <shlobj.h> #include <shlobj.h>
#include <WtExeUtils.h> #include <WtExeUtils.h>
#include <aclapi.h>
#include <sddl.h>
#include <wil/token_helpers.h>
static constexpr std::string_view Utf8Bom{ u8"\uFEFF" }; static constexpr std::string_view Utf8Bom{ u8"\uFEFF" };
static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" }; static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" };
@ -39,86 +43,44 @@ namespace winrt::Microsoft::Terminal::Settings::Model
return baseSettingsPath; return baseSettingsPath;
} }
locked_hfile OpenFileReadSharedLocked(const std::filesystem::path& path) // Function Description:
// - Checks the permissions on this file, to make sure it can only be opened
// for writing by admins. We will be checking to see if the file is owned
// by the Builtin\Administrators group. If it's not, then it was likely
// tampered with.
// Arguments:
// - handle: a HANDLE to the file to check
// Return Value:
// - true if it had the expected permissions. False otherwise.
static bool _isOwnedByAdministrators(const HANDLE& handle)
{ {
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr) }; // If the file is owned by the administrators group, trust the
THROW_LAST_ERROR_IF(!file); // administrators instead of checking the DACL permissions. It's simpler
// just lock the entire file // and more flexible.
OVERLAPPED sOverlapped;
sOverlapped.Offset = 0; wil::unique_hlocal_security_descriptor sd;
sOverlapped.OffsetHigh = 0; PSID psidOwner{ nullptr };
// Shared lock // The psidOwner pointer references the security descriptor, so it
THROW_LAST_ERROR_IF(!LockFileEx(file.get(), // doesn't have to be freed separate from sd.
0, // lock shared, wait to return until lock is obtained const auto status = GetSecurityInfo(handle,
0, // reserved, does nothing SE_FILE_OBJECT,
INT_MAX, // lock INT_MAX bytes OWNER_SECURITY_INFORMATION,
0, // higher-order bytes, if our state file is greater than 2GB I guess this will be a problem &psidOwner,
&sOverlapped)); nullptr,
return { std::move(file), sOverlapped }; nullptr,
nullptr,
wil::out_param_ptr<PSECURITY_DESCRIPTOR*>(sd));
THROW_IF_WIN32_ERROR(status);
wil::unique_any_psid psidAdmins{ nullptr };
THROW_IF_WIN32_BOOL_FALSE(
ConvertStringSidToSidW(L"BA", wil::out_param_ptr<PSID*>(psidAdmins)));
return EqualSid(psidOwner, psidAdmins.get());
} }
locked_hfile OpenFileRWExclusiveLocked(const std::filesystem::path& path)
{
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) };
THROW_LAST_ERROR_IF(!file);
// just lock the entire file
OVERLAPPED sOverlapped;
sOverlapped.Offset = 0;
sOverlapped.OffsetHigh = 0;
// Shared lock
THROW_LAST_ERROR_IF(!LockFileEx(file.get(),
LOCKFILE_EXCLUSIVE_LOCK, // lock exclusive, wait to return until lock is obtained
0, // reserved, does nothing
INT_MAX, // lock INT_MAX bytes
0, // higher-order bytes, if our state file is greater than 2GB I guess this will be a problem
&sOverlapped));
return { std::move(file), sOverlapped };
}
std::string ReadUTF8FileLocked(const locked_hfile& file)
{
const auto fileSize = GetFileSize(file.get(), nullptr);
THROW_LAST_ERROR_IF(fileSize == INVALID_FILE_SIZE);
// By making our buffer just slightly larger we can detect if
// the file size changed and we've failed to read the full file.
std::string buffer(static_cast<size_t>(fileSize) + 1, '\0');
DWORD bytesRead = 0;
THROW_IF_WIN32_BOOL_FALSE(ReadFile(file.get(), buffer.data(), gsl::narrow<DWORD>(buffer.size()), &bytesRead, nullptr));
// As mentioned before our buffer was allocated oversized.
buffer.resize(bytesRead);
if (til::starts_with(buffer, Utf8Bom))
{
// Yeah this memmove()s the entire content.
// But I don't really want to deal with UTF8 BOMs any more than necessary,
// as basically not a single editor writes a BOM for UTF8.
buffer.erase(0, Utf8Bom.size());
}
return buffer;
}
void WriteUTF8FileLocked(const locked_hfile& file, const std::string_view& content)
{
// truncate the file because we want to overwrite it
SetFilePointer(file.get(), 0, nullptr, FILE_BEGIN);
THROW_IF_WIN32_BOOL_FALSE(SetEndOfFile(file.get()));
const auto fileSize = gsl::narrow<DWORD>(content.size());
DWORD bytesWritten = 0;
THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), content.data(), fileSize, &bytesWritten, nullptr));
if (bytesWritten != fileSize)
{
THROW_WIN32_MSG(ERROR_WRITE_FAULT, "failed to write whole file");
}
}
// Tries to read a file somewhat atomically without locking it. // Tries to read a file somewhat atomically without locking it.
// Strips the UTF8 BOM if it exists. // Strips the UTF8 BOM if it exists.
std::string ReadUTF8File(const std::filesystem::path& path) std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly)
{ {
// From some casual observations we can determine that: // From some casual observations we can determine that:
// * ReadFile() always returns the requested amount of data (unless the file is smaller) // * ReadFile() always returns the requested amount of data (unless the file is smaller)
@ -126,9 +88,40 @@ namespace winrt::Microsoft::Terminal::Settings::Model
// -> Lets add a retry-loop just in case, to not fail if the file size changed while reading. // -> Lets add a retry-loop just in case, to not fail if the file size changed while reading.
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
{ {
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr) }; wil::unique_hfile file{ CreateFileW(path.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
nullptr) };
THROW_LAST_ERROR_IF(!file); THROW_LAST_ERROR_IF(!file);
// Open the file _first_, then check if it has the right
// permissions. This prevents a "Time-of-check to time-of-use"
// vulnerability where a malicious exe could delete the file and
// replace it between us checking the permissions, and reading the
// contents. We've got a handle to the file now, which means we're
// going to read the contents of that instance of the file
// regardless. If someone replaces the file on us before we get to
// the GetSecurityInfo call below, then only the subsequent call to
// ReadUTF8File will notice it.
if (elevatedOnly)
{
const bool hadExpectedPermissions{ _isOwnedByAdministrators(file.get()) };
if (!hadExpectedPermissions)
{
// Close the handle
file.reset();
// delete the file. It's been compromised.
LOG_LAST_ERROR_IF(!DeleteFile(path.c_str()));
// Exit early, because obviously there's nothing to read from the deleted file.
return "";
}
}
const auto fileSize = GetFileSize(file.get(), nullptr); const auto fileSize = GetFileSize(file.get(), nullptr);
THROW_LAST_ERROR_IF(fileSize == INVALID_FILE_SIZE); THROW_LAST_ERROR_IF(fileSize == INVALID_FILE_SIZE);
@ -166,11 +159,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model
} }
// Same as ReadUTF8File, but returns an empty optional, if the file couldn't be opened. // Same as ReadUTF8File, but returns an empty optional, if the file couldn't be opened.
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path) std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path, const bool elevatedOnly)
{ {
try try
{ {
return { ReadUTF8File(path) }; return { ReadUTF8File(path, elevatedOnly) };
} }
catch (const wil::ResultException& exception) catch (const wil::ResultException& exception)
{ {
@ -183,9 +176,70 @@ namespace winrt::Microsoft::Terminal::Settings::Model
} }
} }
void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content) void WriteUTF8File(const std::filesystem::path& path,
const std::string_view& content,
const bool elevatedOnly)
{ {
wil::unique_hfile file{ CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr) }; SECURITY_ATTRIBUTES sa;
// stash the security descriptor here, so it will stay in context until
// after the call to CreateFile. If it gets cleaned up before that, then
// CreateFile will fail
wil::unique_hlocal_security_descriptor sd;
if (elevatedOnly)
{
// Initialize the security descriptor so only admins can write the
// file. We'll initialize the SECURITY_DESCRIPTOR with a
// single entry (ACE) -- a mandatory label (i.e. a
// LABEL_SECURITY_INFORMATION) that sets the file integrity level to
// "high", with a no-write-up policy.
//
// When accessed from a security context at a lower integrity level,
// the no-write-up policy filters out rights that aren't in the
// object type's generic read and execute set (for the file type,
// that's FILE_GENERIC_READ | FILE_GENERIC_EXECUTE).
//
// Another option we considered here was manually setting the ACLs
// on this file such that Builtin\Admins could read&write the file,
// and all users could only read.
//
// Big thanks to @eryksun in GH#11222 for helping with this. This
// alternative method was chosen because it's considerably simpler.
// The required security descriptor can be created easily from the
// SDDL string: "S:(ML;;NW;;;HI)"
// (i.e. SACL:mandatory label;;no write up;;;high integrity level)
unsigned long cb;
THROW_IF_WIN32_BOOL_FALSE(
ConvertStringSecurityDescriptorToSecurityDescriptor(L"S:(ML;;NW;;;HI)",
SDDL_REVISION_1,
wil::out_param_ptr<PSECURITY_DESCRIPTOR*>(sd),
&cb));
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = sd.get();
sa.bInheritHandle = false;
// If we're running in an elevated context, when this file is
// created, it will automatically be owned by
// Builtin\Administrators, which will pass the above
// _isOwnedByAdministrators check.
//
// Programs running in an elevated context will be free to write the
// file, and unelevated processes will be able to read the file. An
// unelevated process could always delete the file and rename a new
// file in it's place (a la the way `vim.exe` saves files), but if
// they do that, the new file _won't_ be owned by Administrators,
// failing the above check.
}
wil::unique_hfile file{ CreateFileW(path.c_str(),
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_DELETE,
elevatedOnly ? &sa : nullptr,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
nullptr) };
THROW_LAST_ERROR_IF(!file); THROW_LAST_ERROR_IF(!file);
const auto fileSize = gsl::narrow<DWORD>(content.size()); const auto fileSize = gsl::narrow<DWORD>(content.size());
@ -198,7 +252,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model
} }
} }
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content) void WriteUTF8FileAtomic(const std::filesystem::path& path,
const std::string_view& content)
{ {
// GH#10787: rename() will replace symbolic links themselves and not the path they point at. // GH#10787: rename() will replace symbolic links themselves and not the path they point at.
// It's thus important that we first resolve them before generating temporary path. // It's thus important that we first resolve them before generating temporary path.

View file

@ -1,41 +1,11 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT license. // Licensed under the MIT license.
#pragma once
namespace winrt::Microsoft::Terminal::Settings::Model namespace winrt::Microsoft::Terminal::Settings::Model
{ {
// I couldn't find a wil helper for this so I made it myself
class locked_hfile
{
public:
wil::unique_hfile file;
OVERLAPPED lockedRegion;
~locked_hfile()
{
if (file)
{
// Need to unlock the file before it is closed
UnlockFileEx(file.get(), 0, INT_MAX, 0, &lockedRegion);
}
}
HANDLE get() const noexcept
{
return file.get();
}
};
std::filesystem::path GetBaseSettingsPath(); std::filesystem::path GetBaseSettingsPath();
std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly = false);
locked_hfile OpenFileReadSharedLocked(const std::filesystem::path& path); std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path, const bool elevatedOnly = false);
locked_hfile OpenFileRWExclusiveLocked(const std::filesystem::path& path); void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content, const bool elevatedOnly = false);
std::string ReadUTF8FileLocked(const locked_hfile& file);
void WriteUTF8FileLocked(const locked_hfile& file, const std::string_view& content);
std::string ReadUTF8File(const std::filesystem::path& path);
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path);
void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content);
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content); void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content);
} }

View file

@ -12,11 +12,6 @@ using namespace Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation; using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
static constexpr std::string_view FontInfoKey{ "font" }; static constexpr std::string_view FontInfoKey{ "font" };
static constexpr std::string_view FontFaceKey{ "face" };
static constexpr std::string_view FontSizeKey{ "size" };
static constexpr std::string_view FontWeightKey{ "weight" };
static constexpr std::string_view FontFeaturesKey{ "features" };
static constexpr std::string_view FontAxesKey{ "axes" };
static constexpr std::string_view LegacyFontFaceKey{ "fontFace" }; static constexpr std::string_view LegacyFontFaceKey{ "fontFace" };
static constexpr std::string_view LegacyFontSizeKey{ "fontSize" }; static constexpr std::string_view LegacyFontSizeKey{ "fontSize" };
static constexpr std::string_view LegacyFontWeightKey{ "fontWeight" }; static constexpr std::string_view LegacyFontWeightKey{ "fontWeight" };
@ -29,11 +24,12 @@ winrt::Microsoft::Terminal::Settings::Model::implementation::FontConfig::FontCon
winrt::com_ptr<FontConfig> FontConfig::CopyFontInfo(const FontConfig* source, winrt::weak_ref<Profile> sourceProfile) winrt::com_ptr<FontConfig> FontConfig::CopyFontInfo(const FontConfig* source, winrt::weak_ref<Profile> sourceProfile)
{ {
auto fontInfo{ winrt::make_self<FontConfig>(std::move(sourceProfile)) }; auto fontInfo{ winrt::make_self<FontConfig>(std::move(sourceProfile)) };
fontInfo->_FontFace = source->_FontFace;
fontInfo->_FontSize = source->_FontSize; #define FONT_SETTINGS_COPY(type, name, jsonKey, ...) \
fontInfo->_FontWeight = source->_FontWeight; fontInfo->_##name = source->_##name;
fontInfo->_FontAxes = source->_FontAxes; MTSM_FONT_SETTINGS(FONT_SETTINGS_COPY)
fontInfo->_FontFeatures = source->_FontFeatures; #undef FONT_SETTINGS_COPY
return fontInfo; return fontInfo;
} }
@ -41,11 +37,10 @@ Json::Value FontConfig::ToJson() const
{ {
Json::Value json{ Json::ValueType::objectValue }; Json::Value json{ Json::ValueType::objectValue };
JsonUtils::SetValueForKey(json, FontFaceKey, _FontFace); #define FONT_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
JsonUtils::SetValueForKey(json, FontSizeKey, _FontSize); JsonUtils::SetValueForKey(json, jsonKey, _##name);
JsonUtils::SetValueForKey(json, FontWeightKey, _FontWeight); MTSM_FONT_SETTINGS(FONT_SETTINGS_TO_JSON)
JsonUtils::SetValueForKey(json, FontAxesKey, _FontAxes); #undef FONT_SETTINGS_TO_JSON
JsonUtils::SetValueForKey(json, FontFeaturesKey, _FontFeatures);
return json; return json;
} }
@ -69,11 +64,10 @@ void FontConfig::LayerJson(const Json::Value& json)
{ {
// A font object is defined, use that // A font object is defined, use that
const auto fontInfoJson = json[JsonKey(FontInfoKey)]; const auto fontInfoJson = json[JsonKey(FontInfoKey)];
JsonUtils::GetValueForKey(fontInfoJson, FontFaceKey, _FontFace); #define FONT_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
JsonUtils::GetValueForKey(fontInfoJson, FontSizeKey, _FontSize); JsonUtils::GetValueForKey(fontInfoJson, jsonKey, _##name);
JsonUtils::GetValueForKey(fontInfoJson, FontWeightKey, _FontWeight); MTSM_FONT_SETTINGS(FONT_SETTINGS_LAYER_JSON)
JsonUtils::GetValueForKey(fontInfoJson, FontFeaturesKey, _FontFeatures); #undef FONT_SETTINGS_LAYER_JSON
JsonUtils::GetValueForKey(fontInfoJson, FontAxesKey, _FontAxes);
} }
else else
{ {

View file

@ -19,6 +19,7 @@ Author(s):
#include "pch.h" #include "pch.h"
#include "FontConfig.g.h" #include "FontConfig.g.h"
#include "JsonUtils.h" #include "JsonUtils.h"
#include "MTSMSettings.h"
#include "../inc/cppwinrt_utils.h" #include "../inc/cppwinrt_utils.h"
#include "IInheritable.h" #include "IInheritable.h"
#include <DefaultSettings.h> #include <DefaultSettings.h>
@ -39,11 +40,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Model::Profile SourceProfile(); Model::Profile SourceProfile();
INHERITABLE_SETTING(Model::FontConfig, hstring, FontFace, DEFAULT_FONT_FACE); #define FONT_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
INHERITABLE_SETTING(Model::FontConfig, int32_t, FontSize, DEFAULT_FONT_SIZE); INHERITABLE_SETTING(Model::FontConfig, type, name, ##__VA_ARGS__)
INHERITABLE_SETTING(Model::FontConfig, Windows::UI::Text::FontWeight, FontWeight, DEFAULT_FONT_WEIGHT); MTSM_FONT_SETTINGS(FONT_SETTINGS_INITIALIZE)
INHERITABLE_SETTING(Model::FontConfig, IFontAxesMap, FontAxes); #undef FONT_SETTINGS_INITIALIZE
INHERITABLE_SETTING(Model::FontConfig, IFontFeatureMap, FontFeatures);
private: private:
winrt::weak_ref<Profile> _sourceProfile; winrt::weak_ref<Profile> _sourceProfile;

View file

@ -18,48 +18,7 @@ using namespace winrt::Microsoft::UI::Xaml::Controls;
static constexpr std::string_view LegacyKeybindingsKey{ "keybindings" }; static constexpr std::string_view LegacyKeybindingsKey{ "keybindings" };
static constexpr std::string_view ActionsKey{ "actions" }; static constexpr std::string_view ActionsKey{ "actions" };
static constexpr std::string_view DefaultProfileKey{ "defaultProfile" }; static constexpr std::string_view DefaultProfileKey{ "defaultProfile" };
static constexpr std::string_view AlwaysShowTabsKey{ "alwaysShowTabs" };
static constexpr std::string_view InitialRowsKey{ "initialRows" };
static constexpr std::string_view InitialColsKey{ "initialCols" };
static constexpr std::string_view InitialPositionKey{ "initialPosition" };
static constexpr std::string_view CenterOnLaunchKey{ "centerOnLaunch" };
static constexpr std::string_view ShowTitleInTitlebarKey{ "showTerminalTitleInTitlebar" };
static constexpr std::string_view LanguageKey{ "language" };
static constexpr std::string_view ThemeKey{ "theme" };
static constexpr std::string_view TabWidthModeKey{ "tabWidthMode" };
static constexpr std::string_view UseAcrylicInTabRowKey{ "useAcrylicInTabRow" };
static constexpr std::string_view ShowTabsInTitlebarKey{ "showTabsInTitlebar" };
static constexpr std::string_view WordDelimitersKey{ "wordDelimiters" };
static constexpr std::string_view InputServiceWarningKey{ "inputServiceWarning" };
static constexpr std::string_view CopyOnSelectKey{ "copyOnSelect" };
static constexpr std::string_view CopyFormattingKey{ "copyFormatting" };
static constexpr std::string_view WarnAboutLargePasteKey{ "largePasteWarning" };
static constexpr std::string_view WarnAboutMultiLinePasteKey{ "multiLinePasteWarning" };
static constexpr std::string_view TrimPasteKey{ "trimPaste" };
static constexpr std::string_view LaunchModeKey{ "launchMode" };
static constexpr std::string_view ConfirmCloseAllKey{ "confirmCloseAllTabs" };
static constexpr std::string_view SnapToGridOnResizeKey{ "snapToGridOnResize" };
static constexpr std::string_view EnableStartupTaskKey{ "startOnUserLogin" };
static constexpr std::string_view FirstWindowPreferenceKey{ "firstWindowPreference" };
static constexpr std::string_view AlwaysOnTopKey{ "alwaysOnTop" };
static constexpr std::string_view LegacyUseTabSwitcherModeKey{ "useTabSwitcher" }; static constexpr std::string_view LegacyUseTabSwitcherModeKey{ "useTabSwitcher" };
static constexpr std::string_view TabSwitcherModeKey{ "tabSwitcherMode" };
static constexpr std::string_view DisableAnimationsKey{ "disableAnimations" };
static constexpr std::string_view StartupActionsKey{ "startupActions" };
static constexpr std::string_view FocusFollowMouseKey{ "focusFollowMouse" };
static constexpr std::string_view WindowingBehaviorKey{ "windowingBehavior" };
static constexpr std::string_view TrimBlockSelectionKey{ "trimBlockSelection" };
static constexpr std::string_view AlwaysShowNotificationIconKey{ "alwaysShowNotificationIcon" };
static constexpr std::string_view MinimizeToNotificationAreaKey{ "minimizeToNotificationArea" };
static constexpr std::string_view DisabledProfileSourcesKey{ "disabledProfileSources" };
static constexpr std::string_view ShowAdminShieldKey{ "showAdminShield" };
static constexpr std::string_view DebugFeaturesKey{ "debugFeatures" };
static constexpr std::string_view ForceFullRepaintRenderingKey{ "experimental.rendering.forceFullRepaint" };
static constexpr std::string_view SoftwareRenderingKey{ "experimental.rendering.software" };
static constexpr std::string_view ForceVTInputKey{ "experimental.input.forceVT" };
static constexpr std::string_view DetectURLsKey{ "experimental.detectURLs" };
// Method Description: // Method Description:
// - Copies any extraneous data from the parent before completing a CreateChild call // - Copies any extraneous data from the parent before completing a CreateChild call
@ -86,45 +45,6 @@ void GlobalAppSettings::_FinalizeInheritance()
winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
{ {
auto globals{ winrt::make_self<GlobalAppSettings>() }; auto globals{ winrt::make_self<GlobalAppSettings>() };
globals->_InitialRows = _InitialRows;
globals->_InitialCols = _InitialCols;
globals->_AlwaysShowTabs = _AlwaysShowTabs;
globals->_ShowTitleInTitlebar = _ShowTitleInTitlebar;
globals->_ConfirmCloseAllTabs = _ConfirmCloseAllTabs;
globals->_Language = _Language;
globals->_Theme = _Theme;
globals->_TabWidthMode = _TabWidthMode;
globals->_UseAcrylicInTabRow = _UseAcrylicInTabRow;
globals->_ShowTabsInTitlebar = _ShowTabsInTitlebar;
globals->_WordDelimiters = _WordDelimiters;
globals->_InputServiceWarning = _InputServiceWarning;
globals->_CopyOnSelect = _CopyOnSelect;
globals->_CopyFormatting = _CopyFormatting;
globals->_WarnAboutLargePaste = _WarnAboutLargePaste;
globals->_WarnAboutMultiLinePaste = _WarnAboutMultiLinePaste;
globals->_TrimPaste = _TrimPaste;
globals->_InitialPosition = _InitialPosition;
globals->_CenterOnLaunch = _CenterOnLaunch;
globals->_LaunchMode = _LaunchMode;
globals->_SnapToGridOnResize = _SnapToGridOnResize;
globals->_ForceFullRepaintRendering = _ForceFullRepaintRendering;
globals->_SoftwareRendering = _SoftwareRendering;
globals->_ForceVTInput = _ForceVTInput;
globals->_DebugFeaturesEnabled = _DebugFeaturesEnabled;
globals->_StartOnUserLogin = _StartOnUserLogin;
globals->_FirstWindowPreference = _FirstWindowPreference;
globals->_AlwaysOnTop = _AlwaysOnTop;
globals->_TabSwitcherMode = _TabSwitcherMode;
globals->_DisableAnimations = _DisableAnimations;
globals->_StartupActions = _StartupActions;
globals->_FocusFollowMouse = _FocusFollowMouse;
globals->_WindowingBehavior = _WindowingBehavior;
globals->_TrimBlockSelection = _TrimBlockSelection;
globals->_DetectURLs = _DetectURLs;
globals->_MinimizeToNotificationArea = _MinimizeToNotificationArea;
globals->_AlwaysShowNotificationIcon = _AlwaysShowNotificationIcon;
globals->_DisabledProfileSources = _DisabledProfileSources;
globals->_ShowAdminShield = _ShowAdminShield;
globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile; globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile;
@ -132,6 +52,11 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
globals->_actionMap = _actionMap->Copy(); globals->_actionMap = _actionMap->Copy();
globals->_keybindingsWarnings = _keybindingsWarnings; globals->_keybindingsWarnings = _keybindingsWarnings;
#define GLOBAL_SETTINGS_COPY(type, name, jsonKey, ...) \
globals->_##name = _##name;
MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_COPY)
#undef GLOBAL_SETTINGS_COPY
if (_colorSchemes) if (_colorSchemes)
{ {
for (auto kv : _colorSchemes) for (auto kv : _colorSchemes)
@ -189,51 +114,15 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::FromJson(const Json::Value&
void GlobalAppSettings::LayerJson(const Json::Value& json) void GlobalAppSettings::LayerJson(const Json::Value& json)
{ {
JsonUtils::GetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile); JsonUtils::GetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
JsonUtils::GetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs);
JsonUtils::GetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs);
JsonUtils::GetValueForKey(json, InitialRowsKey, _InitialRows);
JsonUtils::GetValueForKey(json, InitialColsKey, _InitialCols);
JsonUtils::GetValueForKey(json, InitialPositionKey, _InitialPosition);
JsonUtils::GetValueForKey(json, CenterOnLaunchKey, _CenterOnLaunch);
JsonUtils::GetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar);
JsonUtils::GetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar);
JsonUtils::GetValueForKey(json, WordDelimitersKey, _WordDelimiters);
JsonUtils::GetValueForKey(json, CopyOnSelectKey, _CopyOnSelect);
JsonUtils::GetValueForKey(json, InputServiceWarningKey, _InputServiceWarning);
JsonUtils::GetValueForKey(json, CopyFormattingKey, _CopyFormatting);
JsonUtils::GetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
JsonUtils::GetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
JsonUtils::GetValueForKey(json, TrimPasteKey, _TrimPaste);
JsonUtils::GetValueForKey(json, FirstWindowPreferenceKey, _FirstWindowPreference);
JsonUtils::GetValueForKey(json, LaunchModeKey, _LaunchMode);
JsonUtils::GetValueForKey(json, LanguageKey, _Language);
JsonUtils::GetValueForKey(json, ThemeKey, _Theme);
JsonUtils::GetValueForKey(json, TabWidthModeKey, _TabWidthMode);
JsonUtils::GetValueForKey(json, UseAcrylicInTabRowKey, _UseAcrylicInTabRow);
JsonUtils::GetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
// GetValueForKey will only override the current value if the key exists
JsonUtils::GetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled);
JsonUtils::GetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering);
JsonUtils::GetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering);
JsonUtils::GetValueForKey(json, ForceVTInputKey, _ForceVTInput);
JsonUtils::GetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin);
JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop);
// GH#8076 - when adding enum values to this key, we also changed it from // GH#8076 - when adding enum values to this key, we also changed it from
// "useTabSwitcher" to "tabSwitcherMode". Continue supporting // "useTabSwitcher" to "tabSwitcherMode". Continue supporting
// "useTabSwitcher", but prefer "tabSwitcherMode" // "useTabSwitcher", but prefer "tabSwitcherMode"
JsonUtils::GetValueForKey(json, LegacyUseTabSwitcherModeKey, _TabSwitcherMode); JsonUtils::GetValueForKey(json, LegacyUseTabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::GetValueForKey(json, TabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::GetValueForKey(json, DisableAnimationsKey, _DisableAnimations);
JsonUtils::GetValueForKey(json, StartupActionsKey, _StartupActions);
JsonUtils::GetValueForKey(json, FocusFollowMouseKey, _FocusFollowMouse);
JsonUtils::GetValueForKey(json, WindowingBehaviorKey, _WindowingBehavior);
JsonUtils::GetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection);
JsonUtils::GetValueForKey(json, DetectURLsKey, _DetectURLs);
JsonUtils::GetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea);
JsonUtils::GetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::GetValueForKey(json, DisabledProfileSourcesKey, _DisabledProfileSources);
JsonUtils::GetValueForKey(json, ShowAdminShieldKey, _ShowAdminShield); #define GLOBAL_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
JsonUtils::GetValueForKey(json, jsonKey, _##name);
MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_LAYER_JSON)
#undef GLOBAL_SETTINGS_LAYER_JSON
static constexpr std::array bindingsKeys{ LegacyKeybindingsKey, ActionsKey }; static constexpr std::array bindingsKeys{ LegacyKeybindingsKey, ActionsKey };
for (const auto& jsonKey : bindingsKeys) for (const auto& jsonKey : bindingsKeys)
@ -293,48 +182,12 @@ Json::Value GlobalAppSettings::ToJson() const
{ {
Json::Value json{ Json::ValueType::objectValue }; Json::Value json{ Json::ValueType::objectValue };
// clang-format off JsonUtils::SetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
JsonUtils::SetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
JsonUtils::SetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs); #define GLOBAL_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
JsonUtils::SetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs); JsonUtils::SetValueForKey(json, jsonKey, _##name);
JsonUtils::SetValueForKey(json, InitialRowsKey, _InitialRows); MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_TO_JSON)
JsonUtils::SetValueForKey(json, InitialColsKey, _InitialCols); #undef GLOBAL_SETTINGS_TO_JSON
JsonUtils::SetValueForKey(json, InitialPositionKey, _InitialPosition);
JsonUtils::SetValueForKey(json, CenterOnLaunchKey, _CenterOnLaunch);
JsonUtils::SetValueForKey(json, ShowTitleInTitlebarKey, _ShowTitleInTitlebar);
JsonUtils::SetValueForKey(json, ShowTabsInTitlebarKey, _ShowTabsInTitlebar);
JsonUtils::SetValueForKey(json, WordDelimitersKey, _WordDelimiters);
JsonUtils::SetValueForKey(json, InputServiceWarningKey, _InputServiceWarning);
JsonUtils::SetValueForKey(json, CopyOnSelectKey, _CopyOnSelect);
JsonUtils::SetValueForKey(json, CopyFormattingKey, _CopyFormatting);
JsonUtils::SetValueForKey(json, WarnAboutLargePasteKey, _WarnAboutLargePaste);
JsonUtils::SetValueForKey(json, WarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste);
JsonUtils::SetValueForKey(json, TrimPasteKey, _TrimPaste);
JsonUtils::SetValueForKey(json, FirstWindowPreferenceKey, _FirstWindowPreference);
JsonUtils::SetValueForKey(json, LaunchModeKey, _LaunchMode);
JsonUtils::SetValueForKey(json, LanguageKey, _Language);
JsonUtils::SetValueForKey(json, ThemeKey, _Theme);
JsonUtils::SetValueForKey(json, TabWidthModeKey, _TabWidthMode);
JsonUtils::SetValueForKey(json, UseAcrylicInTabRowKey, _UseAcrylicInTabRow);
JsonUtils::SetValueForKey(json, SnapToGridOnResizeKey, _SnapToGridOnResize);
JsonUtils::SetValueForKey(json, DebugFeaturesKey, _DebugFeaturesEnabled);
JsonUtils::SetValueForKey(json, ForceFullRepaintRenderingKey, _ForceFullRepaintRendering);
JsonUtils::SetValueForKey(json, SoftwareRenderingKey, _SoftwareRendering);
JsonUtils::SetValueForKey(json, ForceVTInputKey, _ForceVTInput);
JsonUtils::SetValueForKey(json, EnableStartupTaskKey, _StartOnUserLogin);
JsonUtils::SetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop);
JsonUtils::SetValueForKey(json, TabSwitcherModeKey, _TabSwitcherMode);
JsonUtils::SetValueForKey(json, DisableAnimationsKey, _DisableAnimations);
JsonUtils::SetValueForKey(json, StartupActionsKey, _StartupActions);
JsonUtils::SetValueForKey(json, FocusFollowMouseKey, _FocusFollowMouse);
JsonUtils::SetValueForKey(json, WindowingBehaviorKey, _WindowingBehavior);
JsonUtils::SetValueForKey(json, TrimBlockSelectionKey, _TrimBlockSelection);
JsonUtils::SetValueForKey(json, DetectURLsKey, _DetectURLs);
JsonUtils::SetValueForKey(json, MinimizeToNotificationAreaKey, _MinimizeToNotificationArea);
JsonUtils::SetValueForKey(json, AlwaysShowNotificationIconKey, _AlwaysShowNotificationIcon);
JsonUtils::SetValueForKey(json, DisabledProfileSourcesKey, _DisabledProfileSources);
JsonUtils::SetValueForKey(json, ShowAdminShieldKey, _ShowAdminShield);
// clang-format on
json[JsonKey(ActionsKey)] = _actionMap->ToJson(); json[JsonKey(ActionsKey)] = _actionMap->ToJson();
return json; return json;

View file

@ -17,6 +17,7 @@ Author(s):
#include "GlobalAppSettings.g.h" #include "GlobalAppSettings.g.h"
#include "IInheritable.h" #include "IInheritable.h"
#include "MTSMSettings.h"
#include "ActionMap.h" #include "ActionMap.h"
#include "Command.h" #include "Command.h"
@ -61,46 +62,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
DisableAnimations(!invertedDisableAnimationsValue); DisableAnimations(!invertedDisableAnimationsValue);
} }
INHERITABLE_SETTING(Model::GlobalAppSettings, int32_t, InitialRows, DEFAULT_ROWS);
INHERITABLE_SETTING(Model::GlobalAppSettings, int32_t, InitialCols, DEFAULT_COLS);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysShowTabs, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ShowTitleInTitlebar, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ConfirmCloseAllTabs, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, Language);
INHERITABLE_SETTING(Model::GlobalAppSettings, winrt::Windows::UI::Xaml::ElementTheme, Theme, winrt::Windows::UI::Xaml::ElementTheme::Default);
INHERITABLE_SETTING(Model::GlobalAppSettings, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, UseAcrylicInTabRow, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ShowTabsInTitlebar, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, CopyOnSelect, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, InputServiceWarning, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, 0);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, WarnAboutLargePaste, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, WarnAboutMultiLinePaste, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, TrimPaste, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, Model::LaunchPosition, InitialPosition, nullptr, nullptr);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, CenterOnLaunch, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, Model::FirstWindowPreference, FirstWindowPreference, FirstWindowPreference::DefaultProfile);
INHERITABLE_SETTING(Model::GlobalAppSettings, Model::LaunchMode, LaunchMode, LaunchMode::DefaultMode);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, SnapToGridOnResize, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceFullRepaintRendering, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, SoftwareRendering, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ForceVTInput, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DebugFeaturesEnabled, debugFeaturesDefault);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, StartOnUserLogin, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysOnTop, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, Model::TabSwitcherMode, TabSwitcherMode, Model::TabSwitcherMode::InOrder);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DisableAnimations, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, StartupActions, L"");
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, FocusFollowMouse, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, Model::WindowingMode, WindowingBehavior, Model::WindowingMode::UseNew);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, TrimBlockSelection, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, DetectURLs, true);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, MinimizeToNotificationArea, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysShowNotificationIcon, false);
INHERITABLE_SETTING(Model::GlobalAppSettings, winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, nullptr);
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, UnparsedDefaultProfile, L""); INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, UnparsedDefaultProfile, L"");
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, ShowAdminShield, true);
#define GLOBAL_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
INHERITABLE_SETTING(Model::GlobalAppSettings, type, name, ##__VA_ARGS__)
MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_INITIALIZE)
#undef GLOBAL_SETTINGS_INITIALIZE
private: private:
#ifdef NDEBUG #ifdef NDEBUG

View file

@ -391,7 +391,6 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
}; };
template<typename T> template<typename T>
struct ConversionTrait<std::unordered_map<std::string, T>> struct ConversionTrait<std::unordered_map<std::string, T>>
{ {
std::unordered_map<std::string, T> FromJson(const Json::Value& json) const std::unordered_map<std::string, T> FromJson(const Json::Value& json) const

View file

@ -0,0 +1,98 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- MTSMSettings.h
Abstract:
- Contains most of the settings within Terminal Settings Model (global, profile, font, appearance)
- To add a new setting to any one of those classes, simply add it to the respective list below, following the macro format
Author(s):
- Pankaj Bhojwani - October 2021
--*/
#pragma once
// Macro format (defaultArgs are optional):
// (type, name, jsonKey, defaultArgs)
#define MTSM_GLOBAL_SETTINGS(X) \
X(int32_t, InitialRows, "initialRows", 30) \
X(int32_t, InitialCols, "initialCols", 80) \
X(hstring, WordDelimiters, "wordDelimiters", DEFAULT_WORD_DELIMITERS) \
X(bool, CopyOnSelect, "copyOnSelect", false) \
X(bool, FocusFollowMouse, "focusFollowMouse", false) \
X(bool, ForceFullRepaintRendering, "experimental.rendering.forceFullRepaint", false) \
X(bool, SoftwareRendering, "experimental.rendering.software", false) \
X(bool, ForceVTInput, "experimental.input.forceVT", false) \
X(bool, TrimBlockSelection, "trimBlockSelection", false) \
X(bool, DetectURLs, "experimental.detectURLs", true) \
X(bool, AlwaysShowTabs, "alwaysShowTabs", true) \
X(bool, ShowTitleInTitlebar, "showTerminalTitleInTitlebar", true) \
X(bool, ConfirmCloseAllTabs, "confirmCloseAllTabs", true) \
X(hstring, Language, "language") \
X(winrt::Windows::UI::Xaml::ElementTheme, Theme, "theme", winrt::Windows::UI::Xaml::ElementTheme::Default) \
X(winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, TabWidthMode, "tabWidthMode", winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode::Equal) \
X(bool, UseAcrylicInTabRow, "useAcrylicInTabRow", false) \
X(bool, ShowTabsInTitlebar, "showTabsInTitlebar", true) \
X(bool, InputServiceWarning, "inputServiceWarning", true) \
X(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, "copyFormatting", 0) \
X(bool, WarnAboutLargePaste, "largePasteWarning", true) \
X(bool, WarnAboutMultiLinePaste, "multiLinePasteWarning", true) \
X(Model::LaunchPosition, InitialPosition, "initialPosition", nullptr, nullptr) \
X(bool, CenterOnLaunch, "centerOnLaunch", false) \
X(Model::FirstWindowPreference, FirstWindowPreference, "firstWindowPreference", FirstWindowPreference::DefaultProfile) \
X(Model::LaunchMode, LaunchMode, "launchMode", LaunchMode::DefaultMode) \
X(bool, SnapToGridOnResize, "snapToGridOnResize", true) \
X(bool, DebugFeaturesEnabled, "debugFeatures", debugFeaturesDefault) \
X(bool, StartOnUserLogin, "startOnUserLogin", false) \
X(bool, AlwaysOnTop, "alwaysOnTop", false) \
X(Model::TabSwitcherMode, TabSwitcherMode, "tabSwitcherMode", Model::TabSwitcherMode::InOrder) \
X(bool, DisableAnimations, "disableAnimations", false) \
X(hstring, StartupActions, "startupActions", L"") \
X(Model::WindowingMode, WindowingBehavior, "windowingBehavior", Model::WindowingMode::UseNew) \
X(bool, MinimizeToNotificationArea, "minimizeToNotificationArea", false) \
X(bool, AlwaysShowNotificationIcon, "alwaysShowNotificationIcon", false) \
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, "disabledProfileSources", nullptr) \
X(bool, ShowAdminShield, "showAdminShield", true) \
X(bool, TrimPaste, "trimPaste", true)
#define MTSM_PROFILE_SETTINGS(X) \
X(int32_t, HistorySize, "historySize", DEFAULT_HISTORY_SIZE) \
X(bool, SnapOnInput, "snapOnInput", true) \
X(bool, AltGrAliasing, "altGrAliasing", true) \
X(bool, UseAcrylic, "useAcrylic", false) \
X(hstring, Commandline, "commandline", L"%SystemRoot%\\System32\\cmd.exe") \
X(Microsoft::Terminal::Control::ScrollbarState, ScrollState, "scrollbarState", Microsoft::Terminal::Control::ScrollbarState::Visible) \
X(Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, "antialiasingMode", Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale) \
X(hstring, StartingDirectory, "startingDirectory") \
X(bool, SuppressApplicationTitle, "suppressApplicationTitle", false) \
X(guid, ConnectionType, "connectionType") \
X(hstring, Icon, "icon", L"\uE756") \
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Graceful) \
X(hstring, TabTitle, "tabTitle") \
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
X(bool, UseAtlasEngine, "experimental.useAtlasEngine", false) \
X(Windows::Foundation::Collections::IVector<winrt::hstring>, BellSound, "bellSound", nullptr)
#define MTSM_FONT_SETTINGS(X) \
X(hstring, FontFace, "face", DEFAULT_FONT_FACE) \
X(int32_t, FontSize, "size", DEFAULT_FONT_SIZE) \
X(winrt::Windows::UI::Text::FontWeight, FontWeight, "weight", DEFAULT_FONT_WEIGHT) \
X(IFontAxesMap, FontAxes, "axes") \
X(IFontFeatureMap, FontFeatures, "features")
#define MTSM_APPEARANCE_SETTINGS(X) \
X(Core::CursorStyle, CursorShape, "cursorShape", Core::CursorStyle::Bar) \
X(uint32_t, CursorHeight, "cursorHeight", DEFAULT_CURSOR_HEIGHT) \
X(double, BackgroundImageOpacity, "backgroundImageOpacity", 1.0) \
X(winrt::Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, "backgroundImageStretchMode", winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill) \
X(bool, RetroTerminalEffect, "experimental.retroTerminalEffect", false) \
X(hstring, PixelShaderPath, "experimental.pixelShaderPath") \
X(ConvergedAlignment, BackgroundImageAlignment, "backgroundImageAlignment", ConvergedAlignment::Horizontal_Center | ConvergedAlignment::Vertical_Center) \
X(hstring, ColorSchemeName, "colorScheme", L"Campbell") \
X(hstring, BackgroundImagePath, "backgroundImage") \
X(Model::IntenseStyle, IntenseTextStyle, "intenseTextStyle", Model::IntenseStyle::Bright) \
X(bool, AdjustIndistinguishableColors, "adjustIndistinguishableColors", true)

View file

@ -50,6 +50,7 @@
<DependentUpon>GlobalAppSettings.idl</DependentUpon> <DependentUpon>GlobalAppSettings.idl</DependentUpon>
</ClInclude> </ClInclude>
<ClInclude Include="IInheritable.h" /> <ClInclude Include="IInheritable.h" />
<ClInclude Include="MTSMSettings.h" />
<ClInclude Include="IDynamicProfileGenerator.h" /> <ClInclude Include="IDynamicProfileGenerator.h" />
<ClInclude Include="JsonUtils.h" /> <ClInclude Include="JsonUtils.h" />
<ClInclude Include="HashUtils.h" /> <ClInclude Include="HashUtils.h" />

View file

@ -76,6 +76,7 @@
<Filter>json</Filter> <Filter>json</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="IInheritable.h" /> <ClInclude Include="IInheritable.h" />
<ClInclude Include="MTSMSettings.h" />
<ClInclude Include="IconPathConverter.h" /> <ClInclude Include="IconPathConverter.h" />
<ClInclude Include="DefaultTerminal.h" /> <ClInclude Include="DefaultTerminal.h" />
<ClInclude Include="FileUtils.h" /> <ClInclude Include="FileUtils.h" />

View file

@ -26,24 +26,9 @@ static constexpr std::string_view GuidKey{ "guid" };
static constexpr std::string_view SourceKey{ "source" }; static constexpr std::string_view SourceKey{ "source" };
static constexpr std::string_view HiddenKey{ "hidden" }; static constexpr std::string_view HiddenKey{ "hidden" };
static constexpr std::string_view TabTitleKey{ "tabTitle" };
static constexpr std::string_view SuppressApplicationTitleKey{ "suppressApplicationTitle" };
static constexpr std::string_view HistorySizeKey{ "historySize" };
static constexpr std::string_view SnapOnInputKey{ "snapOnInput" };
static constexpr std::string_view AltGrAliasingKey{ "altGrAliasing" };
static constexpr std::string_view ConnectionTypeKey{ "connectionType" };
static constexpr std::string_view CommandlineKey{ "commandline" };
static constexpr std::string_view FontInfoKey{ "font" }; static constexpr std::string_view FontInfoKey{ "font" };
static constexpr std::string_view UseAcrylicKey{ "useAcrylic" };
static constexpr std::string_view ScrollbarStateKey{ "scrollbarState" };
static constexpr std::string_view CloseOnExitKey{ "closeOnExit" };
static constexpr std::string_view PaddingKey{ "padding" }; static constexpr std::string_view PaddingKey{ "padding" };
static constexpr std::string_view StartingDirectoryKey{ "startingDirectory" };
static constexpr std::string_view IconKey{ "icon" };
static constexpr std::string_view AntialiasingModeKey{ "antialiasingMode" };
static constexpr std::string_view TabColorKey{ "tabColor" }; static constexpr std::string_view TabColorKey{ "tabColor" };
static constexpr std::string_view BellStyleKey{ "bellStyle" };
static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" }; static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" };
static constexpr std::string_view BellSoundKey{ "bellSound" }; static constexpr std::string_view BellSoundKey{ "bellSound" };
@ -118,29 +103,18 @@ winrt::com_ptr<Profile> Profile::CopySettings() const
profile->_Name = _Name; profile->_Name = _Name;
profile->_Source = _Source; profile->_Source = _Source;
profile->_Hidden = _Hidden; profile->_Hidden = _Hidden;
profile->_Icon = _Icon;
profile->_CloseOnExit = _CloseOnExit;
profile->_TabTitle = _TabTitle;
profile->_TabColor = _TabColor; profile->_TabColor = _TabColor;
profile->_SuppressApplicationTitle = _SuppressApplicationTitle;
profile->_UseAcrylic = _UseAcrylic;
profile->_ScrollState = _ScrollState;
profile->_Padding = _Padding; profile->_Padding = _Padding;
profile->_Commandline = _Commandline;
profile->_StartingDirectory = _StartingDirectory;
profile->_AntialiasingMode = _AntialiasingMode;
profile->_ForceFullRepaintRendering = _ForceFullRepaintRendering;
profile->_SoftwareRendering = _SoftwareRendering;
profile->_HistorySize = _HistorySize;
profile->_SnapOnInput = _SnapOnInput;
profile->_AltGrAliasing = _AltGrAliasing;
profile->_BellStyle = _BellStyle;
profile->_BellSound = _BellSound;
profile->_ConnectionType = _ConnectionType;
profile->_Origin = _Origin; profile->_Origin = _Origin;
profile->_FontInfo = *fontInfo; profile->_FontInfo = *fontInfo;
profile->_DefaultAppearance = *defaultAppearance; profile->_DefaultAppearance = *defaultAppearance;
#define PROFILE_SETTINGS_COPY(type, name, jsonKey, ...) \
profile->_##name = _##name;
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_COPY)
#undef PROFILE_SETTINGS_COPY
if (_UnfocusedAppearance) if (_UnfocusedAppearance)
{ {
Model::AppearanceConfig unfocused{ nullptr }; Model::AppearanceConfig unfocused{ nullptr };
@ -198,32 +172,17 @@ void Profile::LayerJson(const Json::Value& json)
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden); JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
JsonUtils::GetValueForKey(json, SourceKey, _Source); JsonUtils::GetValueForKey(json, SourceKey, _Source);
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
JsonUtils::GetValueForKey(json, HistorySizeKey, _HistorySize);
JsonUtils::GetValueForKey(json, SnapOnInputKey, _SnapOnInput);
JsonUtils::GetValueForKey(json, AltGrAliasingKey, _AltGrAliasing);
JsonUtils::GetValueForKey(json, TabTitleKey, _TabTitle);
// Control Settings
JsonUtils::GetValueForKey(json, ConnectionTypeKey, _ConnectionType);
JsonUtils::GetValueForKey(json, CommandlineKey, _Commandline);
JsonUtils::GetValueForKey(json, UseAcrylicKey, _UseAcrylic);
JsonUtils::GetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle);
JsonUtils::GetValueForKey(json, CloseOnExitKey, _CloseOnExit);
// Padding was never specified as an integer, but it was a common working mistake. // Padding was never specified as an integer, but it was a common working mistake.
// Allow it to be permissive. // Allow it to be permissive.
JsonUtils::GetValueForKey(json, PaddingKey, _Padding, JsonUtils::OptionalConverter<hstring, JsonUtils::PermissiveStringConverter<std::wstring>>{}); JsonUtils::GetValueForKey(json, PaddingKey, _Padding, JsonUtils::OptionalConverter<hstring, JsonUtils::PermissiveStringConverter<std::wstring>>{});
JsonUtils::GetValueForKey(json, ScrollbarStateKey, _ScrollState);
JsonUtils::GetValueForKey(json, StartingDirectoryKey, _StartingDirectory);
JsonUtils::GetValueForKey(json, IconKey, _Icon);
JsonUtils::GetValueForKey(json, AntialiasingModeKey, _AntialiasingMode);
JsonUtils::GetValueForKey(json, TabColorKey, _TabColor); JsonUtils::GetValueForKey(json, TabColorKey, _TabColor);
JsonUtils::GetValueForKey(json, BellStyleKey, _BellStyle);
JsonUtils::GetValueForKey(json, BellSoundKey, _BellSound); #define PROFILE_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
JsonUtils::GetValueForKey(json, jsonKey, _##name);
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_LAYER_JSON)
#undef PROFILE_SETTINGS_LAYER_JSON
if (json.isMember(JsonKey(UnfocusedAppearanceKey))) if (json.isMember(JsonKey(UnfocusedAppearanceKey)))
{ {
@ -355,29 +314,16 @@ Json::Value Profile::ToJson() const
JsonUtils::SetValueForKey(json, HiddenKey, writeBasicSettings ? Hidden() : _Hidden); JsonUtils::SetValueForKey(json, HiddenKey, writeBasicSettings ? Hidden() : _Hidden);
JsonUtils::SetValueForKey(json, SourceKey, writeBasicSettings ? Source() : _Source); JsonUtils::SetValueForKey(json, SourceKey, writeBasicSettings ? Source() : _Source);
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
JsonUtils::SetValueForKey(json, HistorySizeKey, _HistorySize);
JsonUtils::SetValueForKey(json, SnapOnInputKey, _SnapOnInput);
JsonUtils::SetValueForKey(json, AltGrAliasingKey, _AltGrAliasing);
JsonUtils::SetValueForKey(json, TabTitleKey, _TabTitle);
// Control Settings
JsonUtils::SetValueForKey(json, ConnectionTypeKey, _ConnectionType);
JsonUtils::SetValueForKey(json, CommandlineKey, _Commandline);
JsonUtils::SetValueForKey(json, UseAcrylicKey, _UseAcrylic);
JsonUtils::SetValueForKey(json, SuppressApplicationTitleKey, _SuppressApplicationTitle);
JsonUtils::SetValueForKey(json, CloseOnExitKey, _CloseOnExit);
// PermissiveStringConverter is unnecessary for serialization // PermissiveStringConverter is unnecessary for serialization
JsonUtils::SetValueForKey(json, PaddingKey, _Padding); JsonUtils::SetValueForKey(json, PaddingKey, _Padding);
JsonUtils::SetValueForKey(json, ScrollbarStateKey, _ScrollState);
JsonUtils::SetValueForKey(json, StartingDirectoryKey, _StartingDirectory);
JsonUtils::SetValueForKey(json, IconKey, _Icon);
JsonUtils::SetValueForKey(json, AntialiasingModeKey, _AntialiasingMode);
JsonUtils::SetValueForKey(json, TabColorKey, _TabColor); JsonUtils::SetValueForKey(json, TabColorKey, _TabColor);
JsonUtils::SetValueForKey(json, BellStyleKey, _BellStyle);
JsonUtils::SetValueForKey(json, BellSoundKey, _BellSound); #define PROFILE_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
JsonUtils::SetValueForKey(json, jsonKey, _##name);
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_TO_JSON)
#undef PROFILE_SETTINGS_TO_JSON
// Font settings // Font settings
const auto fontInfoImpl = winrt::get_self<FontConfig>(_FontInfo); const auto fontInfoImpl = winrt::get_self<FontConfig>(_FontInfo);

View file

@ -46,6 +46,7 @@ Author(s):
#include "Profile.g.h" #include "Profile.g.h"
#include "IInheritable.h" #include "IInheritable.h"
#include "MTSMSettings.h"
#include "../inc/cppwinrt_utils.h" #include "../inc/cppwinrt_utils.h"
#include "JsonUtils.h" #include "JsonUtils.h"
@ -102,45 +103,26 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void _FinalizeInheritance() override; void _FinalizeInheritance() override;
// Special fields
WINRT_PROPERTY(bool, Deleted, false); WINRT_PROPERTY(bool, Deleted, false);
WINRT_PROPERTY(OriginTag, Origin, OriginTag::None); WINRT_PROPERTY(OriginTag, Origin, OriginTag::None);
WINRT_PROPERTY(guid, Updates); WINRT_PROPERTY(guid, Updates);
INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
// Nullable/optional settings
INHERITABLE_NULLABLE_SETTING(Model::Profile, Microsoft::Terminal::Core::Color, TabColor, nullptr);
INHERITABLE_SETTING(Model::Profile, Model::IAppearanceConfig, UnfocusedAppearance, nullptr);
// Settings that cannot be put in the macro because of how they are handled in ToJson/LayerJson
INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default"); INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default");
INHERITABLE_SETTING(Model::Profile, hstring, Source); INHERITABLE_SETTING(Model::Profile, hstring, Source);
INHERITABLE_SETTING(Model::Profile, bool, Hidden, false); INHERITABLE_SETTING(Model::Profile, bool, Hidden, false);
INHERITABLE_SETTING(Model::Profile, guid, ConnectionType); INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
// Default Icon: Segoe MDL2 CommandPrompt icon
INHERITABLE_SETTING(Model::Profile, hstring, Icon, L"\uE756");
INHERITABLE_SETTING(Model::Profile, CloseOnExitMode, CloseOnExit, CloseOnExitMode::Graceful);
INHERITABLE_SETTING(Model::Profile, hstring, TabTitle);
INHERITABLE_NULLABLE_SETTING(Model::Profile, Microsoft::Terminal::Core::Color, TabColor, nullptr);
INHERITABLE_SETTING(Model::Profile, bool, SuppressApplicationTitle, false);
INHERITABLE_SETTING(Model::Profile, bool, UseAcrylic, false);
INHERITABLE_SETTING(Model::Profile, Microsoft::Terminal::Control::ScrollbarState, ScrollState, Microsoft::Terminal::Control::ScrollbarState::Visible);
INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING); INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING);
INHERITABLE_SETTING(Model::Profile, hstring, Commandline, L"%SystemRoot%\\System32\\cmd.exe"); #define PROFILE_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
INHERITABLE_SETTING(Model::Profile, hstring, StartingDirectory); INHERITABLE_SETTING(Model::Profile, type, name, ##__VA_ARGS__)
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_INITIALIZE)
INHERITABLE_SETTING(Model::Profile, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale); #undef PROFILE_SETTINGS_INITIALIZE
INHERITABLE_SETTING(Model::Profile, bool, ForceFullRepaintRendering, false);
INHERITABLE_SETTING(Model::Profile, bool, SoftwareRendering, false);
INHERITABLE_SETTING(Model::Profile, int32_t, HistorySize, DEFAULT_HISTORY_SIZE);
INHERITABLE_SETTING(Model::Profile, bool, SnapOnInput, true);
INHERITABLE_SETTING(Model::Profile, bool, AltGrAliasing, true);
INHERITABLE_SETTING(Model::Profile, Model::BellStyle, BellStyle, BellStyle::Audible);
INHERITABLE_SETTING(Model::Profile, Model::IAppearanceConfig, UnfocusedAppearance, nullptr);
INHERITABLE_SETTING(Model::Profile, Windows::Foundation::Collections::IVector<winrt::hstring>, BellSound);
private: private:
Model::IAppearanceConfig _DefaultAppearance{ winrt::make<AppearanceConfig>(weak_ref<Model::Profile>(*this)) }; Model::IAppearanceConfig _DefaultAppearance{ winrt::make<AppearanceConfig>(weak_ref<Model::Profile>(*this)) };

View file

@ -74,14 +74,12 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_PROFILE_SETTING(IAppearanceConfig, UnfocusedAppearance); INHERITABLE_PROFILE_SETTING(IAppearanceConfig, UnfocusedAppearance);
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.TextAntialiasingMode, AntialiasingMode); INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.TextAntialiasingMode, AntialiasingMode);
INHERITABLE_PROFILE_SETTING(Boolean, ForceFullRepaintRendering);
INHERITABLE_PROFILE_SETTING(Boolean, SoftwareRendering);
INHERITABLE_PROFILE_SETTING(Int32, HistorySize); INHERITABLE_PROFILE_SETTING(Int32, HistorySize);
INHERITABLE_PROFILE_SETTING(Boolean, SnapOnInput); INHERITABLE_PROFILE_SETTING(Boolean, SnapOnInput);
INHERITABLE_PROFILE_SETTING(Boolean, AltGrAliasing); INHERITABLE_PROFILE_SETTING(Boolean, AltGrAliasing);
INHERITABLE_PROFILE_SETTING(BellStyle, BellStyle); INHERITABLE_PROFILE_SETTING(BellStyle, BellStyle);
INHERITABLE_PROFILE_SETTING(Boolean, UseAtlasEngine);
INHERITABLE_PROFILE_SETTING(Windows.Foundation.Collections.IVector<String>, BellSound); INHERITABLE_PROFILE_SETTING(Windows.Foundation.Collections.IVector<String>, BellSound);
} }
} }

View file

@ -275,6 +275,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// Fill in the remaining properties from the profile // Fill in the remaining properties from the profile
_ProfileName = profile.Name(); _ProfileName = profile.Name();
_ProfileSource = profile.Source();
_UseAcrylic = profile.UseAcrylic(); _UseAcrylic = profile.UseAcrylic();
_FontFace = profile.FontInfo().FontFace(); _FontFace = profile.FontInfo().FontFace();
@ -297,6 +298,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_SuppressApplicationTitle = profile.SuppressApplicationTitle(); _SuppressApplicationTitle = profile.SuppressApplicationTitle();
} }
_UseAtlasEngine = profile.UseAtlasEngine();
_ScrollState = profile.ScrollState(); _ScrollState = profile.ScrollState();
_AntialiasingMode = profile.AntialiasingMode(); _AntialiasingMode = profile.AntialiasingMode();

View file

@ -119,6 +119,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// ------------------------ End of Core Settings ----------------------- // ------------------------ End of Core Settings -----------------------
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName); INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileSource);
INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAcrylic, false); INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAcrylic, false);
INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0); INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0);
INHERITABLE_SETTING(Model::TerminalSettings, hstring, Padding, DEFAULT_PADDING); INHERITABLE_SETTING(Model::TerminalSettings, hstring, Padding, DEFAULT_PADDING);
@ -146,6 +148,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::TerminalSettings, hstring, EnvironmentVariables); INHERITABLE_SETTING(Model::TerminalSettings, hstring, EnvironmentVariables);
INHERITABLE_SETTING(Model::TerminalSettings, Microsoft::Terminal::Control::ScrollbarState, ScrollState, Microsoft::Terminal::Control::ScrollbarState::Visible); INHERITABLE_SETTING(Model::TerminalSettings, Microsoft::Terminal::Control::ScrollbarState, ScrollState, Microsoft::Terminal::Control::ScrollbarState::Visible);
INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAtlasEngine, false);
INHERITABLE_SETTING(Model::TerminalSettings, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale); INHERITABLE_SETTING(Model::TerminalSettings, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale);

View file

@ -53,3 +53,6 @@ TRACELOGGING_DECLARE_PROVIDER(g_hSettingsModelProvider);
// Manually include til after we include Windows.Foundation to give it winrt superpowers // Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h" #include "til.h"
#include <til/mutex.h>
#include <til/throttled_func.h>

View file

@ -51,6 +51,7 @@ namespace ControlUnitTests
// ------------------------ End of Core Settings ----------------------- // ------------------------ End of Core Settings -----------------------
WINRT_PROPERTY(winrt::hstring, ProfileName); WINRT_PROPERTY(winrt::hstring, ProfileName);
WINRT_PROPERTY(winrt::hstring, ProfileSource);
WINRT_PROPERTY(bool, UseAcrylic, false); WINRT_PROPERTY(bool, UseAcrylic, false);
WINRT_PROPERTY(double, Opacity, .5); WINRT_PROPERTY(double, Opacity, .5);
WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING); WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING);
@ -75,6 +76,7 @@ namespace ControlUnitTests
WINRT_PROPERTY(winrt::hstring, EnvironmentVariables); WINRT_PROPERTY(winrt::hstring, EnvironmentVariables);
WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::ScrollbarState, ScrollState, winrt::Microsoft::Terminal::Control::ScrollbarState::Visible); WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::ScrollbarState, ScrollState, winrt::Microsoft::Terminal::Control::ScrollbarState::Visible);
WINRT_PROPERTY(bool, UseAtlasEngine, false);
WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale); WINRT_PROPERTY(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale);

View file

@ -2901,15 +2901,9 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs()
auto defaultAttrs = si.GetAttributes(); auto defaultAttrs = si.GetAttributes();
auto conhostGreenAttrs = TextAttribute(); auto conhostGreenAttrs = TextAttribute();
conhostGreenAttrs.SetIndexedBackground(TextColor::DARK_GREEN);
// Conhost and Terminal store attributes in different bits.
// conhostGreenAttrs.SetIndexedAttributes(std::nullopt,
// { static_cast<BYTE>(FOREGROUND_GREEN) });
conhostGreenAttrs.SetIndexedBackground(FOREGROUND_GREEN);
auto terminalGreenAttrs = TextAttribute(); auto terminalGreenAttrs = TextAttribute();
// terminalGreenAttrs.SetIndexedAttributes(std::nullopt, terminalGreenAttrs.SetIndexedBackground(TextColor::DARK_GREEN);
// { static_cast<BYTE>(XTERM_GREEN_ATTR) });
terminalGreenAttrs.SetIndexedBackground(XTERM_GREEN_ATTR);
// Use an initial ^[[m to start printing with default-on-default // Use an initial ^[[m to start printing with default-on-default
sm.ProcessString(L"\x1b[m"); sm.ProcessString(L"\x1b[m");
@ -2942,7 +2936,7 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs()
auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool isTerminal, const bool afterResize) { auto verifyBuffer = [&](const TextBuffer& tb, const til::rectangle viewport, const bool isTerminal, const bool afterResize) {
const auto width = viewport.width<short>(); const auto width = viewport.width<short>();
// Conhost and Terminal store attributes in different bits. // Conhost and Terminal attributes are potentially different.
const auto greenAttrs = isTerminal ? terminalGreenAttrs : conhostGreenAttrs; const auto greenAttrs = isTerminal ? terminalGreenAttrs : conhostGreenAttrs;
for (short row = 0; row < tb.GetSize().Height(); row++) for (short row = 0; row < tb.GetSize().Height(); row++)
@ -3034,13 +3028,11 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
auto defaultAttrs = si.GetAttributes(); auto defaultAttrs = si.GetAttributes();
auto conhostBlueAttrs = defaultAttrs; auto conhostBlueAttrs = defaultAttrs;
conhostBlueAttrs.SetIndexedForeground(TextColor::DARK_GREEN);
// Conhost and Terminal store attributes in different bits. conhostBlueAttrs.SetIndexedBackground(TextColor::DARK_BLUE);
conhostBlueAttrs.SetIndexedForeground(FOREGROUND_GREEN);
conhostBlueAttrs.SetIndexedBackground(FOREGROUND_BLUE);
auto terminalBlueAttrs = TextAttribute(); auto terminalBlueAttrs = TextAttribute();
terminalBlueAttrs.SetIndexedForeground(XTERM_GREEN_ATTR); terminalBlueAttrs.SetIndexedForeground(TextColor::DARK_GREEN);
terminalBlueAttrs.SetIndexedBackground(XTERM_BLUE_ATTR); terminalBlueAttrs.SetIndexedBackground(TextColor::DARK_BLUE);
// We're going to print 4 more rows than the entire height of the viewport, // We're going to print 4 more rows than the entire height of the viewport,
// causing the buffer to circle 4 times. This is 2 extra iterations of the // causing the buffer to circle 4 times. This is 2 extra iterations of the
@ -3083,7 +3075,7 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
const auto width = viewport.width<short>(); const auto width = viewport.width<short>();
const auto isTerminal = viewport.top() != 0; const auto isTerminal = viewport.top() != 0;
// Conhost and Terminal store attributes in different bits. // Conhost and Terminal attributes are potentially different.
const auto blueAttrs = isTerminal ? terminalBlueAttrs : conhostBlueAttrs; const auto blueAttrs = isTerminal ? terminalBlueAttrs : conhostBlueAttrs;
for (short row = 0; row < viewport.bottom<short>() - 2; row++) for (short row = 0; row < viewport.bottom<short>() - 2; row++)

View file

@ -84,6 +84,7 @@ AppHost::AppHost() noexcept :
_window->WindowMoved({ this, &AppHost::_WindowMoved }); _window->WindowMoved({ this, &AppHost::_WindowMoved });
_window->HotkeyPressed({ this, &AppHost::_GlobalHotkeyPressed }); _window->HotkeyPressed({ this, &AppHost::_GlobalHotkeyPressed });
_window->SetAlwaysOnTop(_logic.GetInitialAlwaysOnTop()); _window->SetAlwaysOnTop(_logic.GetInitialAlwaysOnTop());
_window->ShouldExitFullscreen({ &_logic, &winrt::TerminalApp::AppLogic::RequestExitFullscreen });
_window->MakeWindow(); _window->MakeWindow();
_GetWindowLayoutRequestedToken = _windowManager.GetWindowLayoutRequested([this](auto&&, const winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs& args) { _GetWindowLayoutRequestedToken = _windowManager.GetWindowLayoutRequested([this](auto&&, const winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs& args) {
@ -325,6 +326,7 @@ void AppHost::Initialize()
_logic.FocusModeChanged({ this, &AppHost::_FocusModeChanged }); _logic.FocusModeChanged({ this, &AppHost::_FocusModeChanged });
_logic.AlwaysOnTopChanged({ this, &AppHost::_AlwaysOnTopChanged }); _logic.AlwaysOnTopChanged({ this, &AppHost::_AlwaysOnTopChanged });
_logic.RaiseVisualBell({ this, &AppHost::_RaiseVisualBell }); _logic.RaiseVisualBell({ this, &AppHost::_RaiseVisualBell });
_logic.SystemMenuChangeRequested({ this, &AppHost::_SystemMenuChangeRequested });
_logic.Create(); _logic.Create();
@ -843,8 +845,30 @@ winrt::Windows::Foundation::IAsyncAction AppHost::_SaveWindowLayouts()
if (_logic.ShouldUsePersistedLayout()) if (_logic.ShouldUsePersistedLayout())
{ {
const auto layoutJsons = _windowManager.GetAllWindowLayouts(); try
_logic.SaveWindowLayoutJsons(layoutJsons); {
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Collect",
TraceLoggingDescription("Logged when collecting window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
const auto layoutJsons = _windowManager.GetAllWindowLayouts();
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Save",
TraceLoggingDescription("Logged when writing window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_logic.SaveWindowLayoutJsons(layoutJsons);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_SaveWindowLayouts_Failed",
TraceLoggingDescription("An error occurred when collecting or writing window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
} }
co_return; co_return;
@ -865,6 +889,12 @@ winrt::fire_and_forget AppHost::_SaveWindowLayoutsRepeat()
// per 10 seconds, if a save is requested by another source simultaneously. // per 10 seconds, if a save is requested by another source simultaneously.
if (_getWindowLayoutThrottler.has_value()) if (_getWindowLayoutThrottler.has_value())
{ {
TraceLoggingWrite(g_hWindowsTerminalProvider,
"AppHost_requestGetLayout",
TraceLoggingDescription("Logged when triggering a throttled write of the window state"),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
_getWindowLayoutThrottler.value()(); _getWindowLayoutThrottler.value()();
} }
} }
@ -1248,6 +1278,27 @@ void AppHost::_OpenSystemMenu(const winrt::Windows::Foundation::IInspectable&,
_window->OpenSystemMenu(std::nullopt, std::nullopt); _window->OpenSystemMenu(std::nullopt, std::nullopt);
} }
void AppHost::_SystemMenuChangeRequested(const winrt::Windows::Foundation::IInspectable&, const winrt::TerminalApp::SystemMenuChangeArgs& args)
{
switch (args.Action())
{
case winrt::TerminalApp::SystemMenuChangeAction::Add:
{
auto handler = args.Handler();
_window->AddToSystemMenu(args.Name(), [handler]() { handler(); });
break;
}
case winrt::TerminalApp::SystemMenuChangeAction::Remove:
{
_window->RemoveFromSystemMenu(args.Name());
break;
}
default:
{
}
}
}
// Method Description: // Method Description:
// - Creates a Notification Icon and hooks up its handlers // - Creates a Notification Icon and hooks up its handlers
// Arguments: // Arguments:

View file

@ -96,6 +96,9 @@ private:
void _OpenSystemMenu(const winrt::Windows::Foundation::IInspectable& sender, void _OpenSystemMenu(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& args); const winrt::Windows::Foundation::IInspectable& args);
void _SystemMenuChangeRequested(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::TerminalApp::SystemMenuChangeArgs& args);
winrt::fire_and_forget _QuitRequested(const winrt::Windows::Foundation::IInspectable& sender, winrt::fire_and_forget _QuitRequested(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& args); const winrt::Windows::Foundation::IInspectable& args);

View file

@ -24,6 +24,7 @@ using namespace ::Microsoft::Console::Types;
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers; using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
#define XAML_HOSTING_WINDOW_CLASS_NAME L"CASCADIA_HOSTING_WINDOW_CLASS" #define XAML_HOSTING_WINDOW_CLASS_NAME L"CASCADIA_HOSTING_WINDOW_CLASS"
#define IDM_SYSTEM_MENU_BEGIN 0x1000
const UINT WM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated"); const UINT WM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated");
@ -321,6 +322,8 @@ void IslandWindow::Initialize()
} }
} }
_systemMenuNextItemId = IDM_SYSTEM_MENU_BEGIN;
// Enable vintage opacity by removing the XAML emergency backstop, GH#603. // Enable vintage opacity by removing the XAML emergency backstop, GH#603.
// We don't really care if this failed or not. // We don't really care if this failed or not.
TerminalTrySetTransparentBackground(true); TerminalTrySetTransparentBackground(true);
@ -608,6 +611,20 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
_NotifyNotificationIconMenuItemSelectedHandlers((HMENU)lparam, (UINT)wparam); _NotifyNotificationIconMenuItemSelectedHandlers((HMENU)lparam, (UINT)wparam);
return 0; return 0;
} }
case WM_SYSCOMMAND:
{
if (wparam == SC_RESTORE && _fullscreen)
{
_ShouldExitFullscreenHandlers();
return 0;
}
auto search = _systemMenuItems.find(LOWORD(wparam));
if (search != _systemMenuItems.end())
{
search->second.callback();
}
break;
}
default: default:
// We'll want to receive this message when explorer.exe restarts // We'll want to receive this message when explorer.exe restarts
// so that we can re-add our icon to the notification area. // so that we can re-add our icon to the notification area.
@ -1717,5 +1734,50 @@ void IslandWindow::OpenSystemMenu(const std::optional<int> mouseX, const std::op
} }
} }
void IslandWindow::AddToSystemMenu(const winrt::hstring& itemLabel, winrt::delegate<void()> callback)
{
const HMENU systemMenu = GetSystemMenu(_window.get(), FALSE);
UINT wID = _systemMenuNextItemId;
MENUITEMINFOW item;
item.cbSize = sizeof(MENUITEMINFOW);
item.fMask = MIIM_STATE | MIIM_ID | MIIM_STRING;
item.fState = MF_ENABLED;
item.wID = wID;
item.dwTypeData = const_cast<LPWSTR>(itemLabel.c_str());
item.cch = static_cast<UINT>(itemLabel.size());
if (LOG_LAST_ERROR_IF(!InsertMenuItemW(systemMenu, wID, FALSE, &item)))
{
return;
}
_systemMenuItems.insert({ wID, { itemLabel, callback } });
_systemMenuNextItemId++;
}
void IslandWindow::RemoveFromSystemMenu(const winrt::hstring& itemLabel)
{
const HMENU systemMenu = GetSystemMenu(_window.get(), FALSE);
int itemCount = GetMenuItemCount(systemMenu);
if (LOG_LAST_ERROR_IF(itemCount == -1))
{
return;
}
auto it = std::find_if(_systemMenuItems.begin(), _systemMenuItems.end(), [&itemLabel](const std::pair<UINT, SystemMenuItemInfo>& elem) {
return elem.second.label == itemLabel;
});
if (it == _systemMenuItems.end())
{
return;
}
if (LOG_LAST_ERROR_IF(!DeleteMenu(systemMenu, it->first, MF_BYCOMMAND)))
{
return;
}
_systemMenuItems.erase(it->first);
}
DEFINE_EVENT(IslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>); DEFINE_EVENT(IslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
DEFINE_EVENT(IslandWindow, WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>); DEFINE_EVENT(IslandWindow, WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);

View file

@ -8,6 +8,12 @@
void SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept; void SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept;
struct SystemMenuItemInfo
{
winrt::hstring label;
winrt::delegate<void()> callback;
};
class IslandWindow : class IslandWindow :
public BaseWindow<IslandWindow> public BaseWindow<IslandWindow>
{ {
@ -54,6 +60,8 @@ public:
void SetMinimizeToNotificationAreaBehavior(bool MinimizeToNotificationArea) noexcept; void SetMinimizeToNotificationAreaBehavior(bool MinimizeToNotificationArea) noexcept;
void OpenSystemMenu(const std::optional<int> mouseX, const std::optional<int> mouseY) const noexcept; void OpenSystemMenu(const std::optional<int> mouseX, const std::optional<int> mouseY) const noexcept;
void AddToSystemMenu(const winrt::hstring& itemLabel, winrt::delegate<void()> callback);
void RemoveFromSystemMenu(const winrt::hstring& itemLabel);
DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>); DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
DECLARE_EVENT(WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>); DECLARE_EVENT(WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);
@ -65,6 +73,7 @@ public:
WINRT_CALLBACK(NotifyShowNotificationIconContextMenu, winrt::delegate<void(til::point)>); WINRT_CALLBACK(NotifyShowNotificationIconContextMenu, winrt::delegate<void(til::point)>);
WINRT_CALLBACK(NotifyNotificationIconMenuItemSelected, winrt::delegate<void(HMENU, UINT)>); WINRT_CALLBACK(NotifyNotificationIconMenuItemSelected, winrt::delegate<void(HMENU, UINT)>);
WINRT_CALLBACK(NotifyReAddNotificationIcon, winrt::delegate<void()>); WINRT_CALLBACK(NotifyReAddNotificationIcon, winrt::delegate<void()>);
WINRT_CALLBACK(ShouldExitFullscreen, winrt::delegate<void()>);
WINRT_CALLBACK(WindowMoved, winrt::delegate<void()>); WINRT_CALLBACK(WindowMoved, winrt::delegate<void()>);
@ -131,6 +140,9 @@ protected:
bool _minimizeToNotificationArea{ false }; bool _minimizeToNotificationArea{ false };
std::unordered_map<UINT, SystemMenuItemInfo> _systemMenuItems;
UINT _systemMenuNextItemId;
private: private:
// This minimum width allows for width the tabs fit // This minimum width allows for width the tabs fit
static constexpr long minimumWidth = 460L; static constexpr long minimumWidth = 460L;

View file

@ -843,7 +843,11 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept
HPAINTBUFFER buf = BeginBufferedPaint(hdc.get(), &rcRest, BPBF_TOPDOWNDIB, &params, &opaqueDc); HPAINTBUFFER buf = BeginBufferedPaint(hdc.get(), &rcRest, BPBF_TOPDOWNDIB, &params, &opaqueDc);
if (!buf || !opaqueDc) if (!buf || !opaqueDc)
{ {
winrt::throw_last_error(); // MSFT:34673647 - BeginBufferedPaint can fail, but it probably
// shouldn't bring the whole Terminal down with it. So don't
// throw_last_error here.
LOG_LAST_ERROR();
return 0;
} }
::FillRect(opaqueDc, &rcRest, _backgroundBrush.get()); ::FillRect(opaqueDc, &rcRest, _backgroundBrush.get());

View file

@ -79,4 +79,14 @@
<!-- This feature will not ship to Stable until it is complete. --> <!-- This feature will not ship to Stable until it is complete. -->
<alwaysDisabledReleaseTokens /> <alwaysDisabledReleaseTokens />
</feature> </feature>
<feature>
<name>Feature_AtlasEngine</name>
<description>If enabled, AtlasEngine and the experimental.useAtlasEngine setting are compiled into the project</description>
<stage>AlwaysEnabled</stage>
<alwaysDisabledBrandingTokens>
<brandingToken>Release</brandingToken>
<brandingToken>WindowsInbox</brandingToken>
</alwaysDisabledBrandingTokens>
</feature>
</featureStaging> </featureStaging>

View file

@ -1,52 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- conattrs.cpp
Abstract:
- Defines common operations on console attributes, especially in regards to
finding the nearest color from a color table.
Author(s):
- Mike Griese (migrie) 01-Sept-2017
--*/
#include "precomp.h"
#include "../inc/conattrs.hpp"
#include <cmath>
// Function Description:
// - Converts the value of a xterm color table index to the windows color table equivalent.
// Arguments:
// - xtermTableEntry: the xterm color table index
// Return Value:
// - The windows color table equivalent.
WORD XtermToWindowsIndex(const size_t xtermTableEntry) noexcept
{
const bool fRed = WI_IsFlagSet(xtermTableEntry, XTERM_RED_ATTR);
const bool fGreen = WI_IsFlagSet(xtermTableEntry, XTERM_GREEN_ATTR);
const bool fBlue = WI_IsFlagSet(xtermTableEntry, XTERM_BLUE_ATTR);
const bool fBright = WI_IsFlagSet(xtermTableEntry, XTERM_BRIGHT_ATTR);
return (fRed ? WINDOWS_RED_ATTR : 0x0) +
(fGreen ? WINDOWS_GREEN_ATTR : 0x0) +
(fBlue ? WINDOWS_BLUE_ATTR : 0x0) +
(fBright ? WINDOWS_BRIGHT_ATTR : 0x0);
}
// Function Description:
// - Converts the value of a xterm color table index to the windows color table
// equivalent. The range of values is [0, 255], where the lowest 16 are
// mapped to the equivalent Windows index, and the rest of the values are
// passed through.
// Arguments:
// - xtermTableEntry: the xterm color table index
// Return Value:
// - The windows color table equivalent.
WORD Xterm256ToWindowsIndex(const size_t xtermTableEntry) noexcept
{
return xtermTableEntry < 16 ? XtermToWindowsIndex(xtermTableEntry) :
static_cast<WORD>(xtermTableEntry);
}

View file

@ -231,7 +231,7 @@ InputBuffer* const CONSOLE_INFORMATION::GetActiveInputBuffer() const
COLORREF CONSOLE_INFORMATION::GetDefaultForeground() const noexcept COLORREF CONSOLE_INFORMATION::GetDefaultForeground() const noexcept
{ {
const auto fg = GetDefaultForegroundColor(); const auto fg = GetDefaultForegroundColor();
return fg != INVALID_COLOR ? fg : GetColorTableEntry(LOBYTE(GetFillAttribute()) & FG_ATTRS); return fg != INVALID_COLOR ? fg : GetLegacyColorTableEntry(LOBYTE(GetFillAttribute()) & FG_ATTRS);
} }
// Method Description: // Method Description:
@ -246,23 +246,37 @@ COLORREF CONSOLE_INFORMATION::GetDefaultForeground() const noexcept
COLORREF CONSOLE_INFORMATION::GetDefaultBackground() const noexcept COLORREF CONSOLE_INFORMATION::GetDefaultBackground() const noexcept
{ {
const auto bg = GetDefaultBackgroundColor(); const auto bg = GetDefaultBackgroundColor();
return bg != INVALID_COLOR ? bg : GetColorTableEntry((LOBYTE(GetFillAttribute()) & BG_ATTRS) >> 4); return bg != INVALID_COLOR ? bg : GetLegacyColorTableEntry((LOBYTE(GetFillAttribute()) & BG_ATTRS) >> 4);
} }
// Method Description: // Method Description:
// - Get the colors of a particular text attribute, using our color table, // - Get the colors of a particular text attribute, using our color table,
// and our configured default attributes. // and our configured default attributes.
// Arguments: // Arguments:
// - attr: the TextAttribute to retrieve the foreground color of. // - attr: the TextAttribute to retrieve the foreground and background color of.
// Return Value: // Return Value:
// - The color values of the attribute's foreground and background. // - The color values of the attribute's foreground and background.
std::pair<COLORREF, COLORREF> CONSOLE_INFORMATION::LookupAttributeColors(const TextAttribute& attr) const noexcept std::pair<COLORREF, COLORREF> CONSOLE_INFORMATION::LookupAttributeColors(const TextAttribute& attr) const noexcept
{
return LookupAttributeColors(attr, GetDefaultForeground(), GetDefaultBackground());
}
// Method Description:
// - Get the colors of a particular text attribute, using our color table,
// and the given default color values.
// Arguments:
// - attr: the TextAttribute to retrieve the foreground and background color of.
// - defaultFg: the COLORREF to use for a default foreground color.
// - defaultBg: the COLORREF to use for a default background color.
// Return Value:
// - The color values of the attribute's foreground and background.
std::pair<COLORREF, COLORREF> CONSOLE_INFORMATION::LookupAttributeColors(const TextAttribute& attr, const COLORREF defaultFg, const COLORREF defaultBg) const noexcept
{ {
_blinkingState.RecordBlinkingUsage(attr); _blinkingState.RecordBlinkingUsage(attr);
return attr.CalculateRgbColors( return attr.CalculateRgbColors(
GetColorTable(), GetColorTable(),
GetDefaultForeground(), defaultFg,
GetDefaultBackground(), defaultBg,
IsScreenReversed(), IsScreenReversed(),
_blinkingState.IsBlinkingFaint()); _blinkingState.IsBlinkingFaint());
} }

View file

@ -43,6 +43,9 @@
<ProjectReference Include="..\..\renderer\base\lib\base.vcxproj"> <ProjectReference Include="..\..\renderer\base\lib\base.vcxproj">
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project> <Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj"> <ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj">
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project> <Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
</ProjectReference> </ProjectReference>

View file

@ -38,6 +38,9 @@
<ProjectReference Include="..\..\renderer\base\lib\base.vcxproj"> <ProjectReference Include="..\..\renderer\base\lib\base.vcxproj">
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project> <Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj"> <ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj">
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project> <Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
</ProjectReference> </ProjectReference>
@ -71,6 +74,7 @@
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>

View file

@ -30,7 +30,7 @@
// GetConsoleAlias // GetConsoleAlias
using namespace WEX::TestExecution; using namespace WEX::TestExecution;
using namespace WEX::Common; using namespace WEX::Common;
using WEX::Logging::Log; using namespace WEX::Logging;
class AliasTests class AliasTests
{ {

View file

@ -5,7 +5,7 @@
extern "C" IMAGE_DOS_HEADER __ImageBase; extern "C" IMAGE_DOS_HEADER __ImageBase;
using WEX::Logging::Log; using namespace WEX::Logging;
using namespace WEX::Common; using namespace WEX::Common;
// This class is intended to test boundary conditions for: // This class is intended to test boundary conditions for:

View file

@ -4,7 +4,7 @@
#include "precomp.h" #include "precomp.h"
using namespace WEX::TestExecution; using namespace WEX::TestExecution;
using WEX::Logging::Log; using namespace WEX::Logging;
using namespace WEX::Common; using namespace WEX::Common;
// This class is intended to test: // This class is intended to test:

View file

@ -7,7 +7,7 @@
#include <future> #include <future>
using WEX::Logging::Log; using namespace WEX::Logging;
using WEX::TestExecution::TestData; using WEX::TestExecution::TestData;
using namespace WEX::Common; using namespace WEX::Common;

View file

@ -5,7 +5,7 @@
using namespace WEX::TestExecution; using namespace WEX::TestExecution;
using namespace WEX::Common; using namespace WEX::Common;
using WEX::Logging::Log; using namespace WEX::Logging;
static const COORD c_coordZero = { 0, 0 }; static const COORD c_coordZero = { 0, 0 };

View file

@ -11,7 +11,7 @@
#define NUMBER_OF_SCENARIO_INPUTS 10 #define NUMBER_OF_SCENARIO_INPUTS 10
#define READ_BATCH 3 #define READ_BATCH 3
using WEX::Logging::Log; using namespace WEX::Logging;
using namespace WEX::Common; using namespace WEX::Common;
// This class is intended to test: // This class is intended to test:

View file

@ -11,7 +11,7 @@
using namespace Microsoft::Console::Types; using namespace Microsoft::Console::Types;
using namespace WEX::TestExecution; using namespace WEX::TestExecution;
using WEX::Logging::Log; using namespace WEX::Logging;
using namespace WEX::Common; using namespace WEX::Common;
class OutputTests class OutputTests

View file

@ -3,7 +3,7 @@
#include "precomp.h" #include "precomp.h"
using WEX::Logging::Log; using namespace WEX::Logging;
// This class is intended to test restrictions placed on APIs from within a UWP application context // This class is intended to test restrictions placed on APIs from within a UWP application context
class PolicyTests class PolicyTests

View file

@ -3,7 +3,7 @@
#include "precomp.h" #include "precomp.h"
using WEX::Logging::Log; using namespace WEX::Logging;
using namespace WEX::Common; using namespace WEX::Common;
// This class is intended to test: // This class is intended to test:

View file

@ -10,7 +10,7 @@
#define ENGLISH_US_CP 437u #define ENGLISH_US_CP 437u
#define JAPANESE_CP 932u #define JAPANESE_CP 932u
using WEX::Logging::Log; using namespace WEX::Logging;
using WEX::TestExecution::TestData; using WEX::TestExecution::TestData;
using namespace WEX::Common; using namespace WEX::Common;
@ -2320,9 +2320,6 @@ void ReadStringWithReadConsoleInputAHelper(HANDLE hIn, PCSTR pszExpectedText, si
while (cchRead < cchExpectedText) while (cchRead < cchExpectedText)
{ {
// expected read is either the size of the buffer or the number of characters remaining, whichever is smaller.
DWORD const dwReadExpected = (DWORD)std::min(cbBuffer, cchExpectedText - cchRead);
DWORD dwRead; DWORD dwRead;
if (!VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleInputA(hIn, irRead, (DWORD)cbBuffer, &dwRead), L"Attempt to read input into buffer.")) if (!VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleInputA(hIn, irRead, (DWORD)cbBuffer, &dwRead), L"Attempt to read input into buffer."))
{ {

View file

@ -3,7 +3,7 @@
#include "precomp.h" #include "precomp.h"
using WEX::Logging::Log; using namespace WEX::Logging;
using namespace WEX::Common; using namespace WEX::Common;
// This class is intended to provide a canary (simple launch test) // This class is intended to provide a canary (simple launch test)

View file

@ -3,7 +3,7 @@
#include "precomp.h" #include "precomp.h"
using WEX::Logging::Log; using namespace WEX::Logging;
using namespace WEX::Common; using namespace WEX::Common;
HANDLE Common::_hConsole = INVALID_HANDLE_VALUE; HANDLE Common::_hConsole = INVALID_HANDLE_VALUE;

View file

@ -25,7 +25,7 @@
using namespace WEX::TestExecution; using namespace WEX::TestExecution;
using namespace WEX::Common; using namespace WEX::Common;
using WEX::Logging::Log; using namespace WEX::Logging;
class KeyPressTests class KeyPressTests
{ {

View file

@ -605,7 +605,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
for (size_t i = 0; i < std::size(data.ColorTable); i++) for (size_t i = 0; i < std::size(data.ColorTable); i++)
{ {
gci.SetColorTableEntry(i, data.ColorTable[i]); gci.SetLegacyColorTableEntry(i, data.ColorTable[i]);
} }
context.SetDefaultAttributes(TextAttribute{ data.wAttributes }, TextAttribute{ data.wPopupAttributes }); context.SetDefaultAttributes(TextAttribute{ data.wAttributes }, TextAttribute{ data.wPopupAttributes });
@ -1978,7 +1978,7 @@ void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo)
Globals& g = ServiceLocator::LocateGlobals(); Globals& g = ServiceLocator::LocateGlobals();
CONSOLE_INFORMATION& gci = g.getConsoleInformation(); CONSOLE_INFORMATION& gci = g.getConsoleInformation();
value = gci.GetColorTableEntry(::Xterm256ToWindowsIndex(index)); value = gci.GetColorTableEntry(index);
return S_OK; return S_OK;
} }
@ -2004,7 +2004,7 @@ void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo)
Globals& g = ServiceLocator::LocateGlobals(); Globals& g = ServiceLocator::LocateGlobals();
CONSOLE_INFORMATION& gci = g.getConsoleInformation(); CONSOLE_INFORMATION& gci = g.getConsoleInformation();
gci.SetColorTableEntry(::Xterm256ToWindowsIndex(index), value); gci.SetColorTableEntry(index, value);
// Update the screen colors if we're not a pty // Update the screen colors if we're not a pty
// No need to force a redraw in pty mode. // No need to force a redraw in pty mode.

View file

@ -22,10 +22,7 @@ Revision History:
#include "ConsoleArguments.hpp" #include "ConsoleArguments.hpp"
#include "ApiRoutines.h" #include "ApiRoutines.h"
#include "../renderer/inc/IRenderData.hpp" #include "../renderer/base/Renderer.hpp"
#include "../renderer/inc/IRenderEngine.hpp"
#include "../renderer/inc/IRenderer.hpp"
#include "../renderer/inc/IFontDefaultList.hpp"
#include "../server/DeviceComm.h" #include "../server/DeviceComm.h"
#include "../server/ConDrvDeviceComm.h" #include "../server/ConDrvDeviceComm.h"
@ -62,7 +59,7 @@ public:
std::vector<wchar_t> WordDelimiters; std::vector<wchar_t> WordDelimiters;
Microsoft::Console::Render::IRenderer* pRender; Microsoft::Console::Render::Renderer* pRender;
Microsoft::Console::Render::IFontDefaultList* pFontDefaultList; Microsoft::Console::Render::IFontDefaultList* pFontDefaultList;

View file

@ -7,7 +7,6 @@
<ClCompile Include="..\CommandListPopup.cpp" /> <ClCompile Include="..\CommandListPopup.cpp" />
<ClCompile Include="..\CopyFromCharPopup.cpp" /> <ClCompile Include="..\CopyFromCharPopup.cpp" />
<ClCompile Include="..\CopyToCharPopup.cpp" /> <ClCompile Include="..\CopyToCharPopup.cpp" />
<ClCompile Include="..\conattrs.cpp" />
<ClCompile Include="..\ConsoleArguments.cpp" /> <ClCompile Include="..\ConsoleArguments.cpp" />
<ClCompile Include="..\CursorBlinker.cpp" /> <ClCompile Include="..\CursorBlinker.cpp" />
<ClCompile Include="..\readDataCooked.cpp" /> <ClCompile Include="..\readDataCooked.cpp" />

View file

@ -138,9 +138,6 @@
<ClCompile Include="..\writeData.cpp"> <ClCompile Include="..\writeData.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\conattrs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\VtInputThread.cpp"> <ClCompile Include="..\VtInputThread.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>

View file

@ -34,13 +34,13 @@ using Microsoft::Console::Interactivity::ServiceLocator;
// - OriginalCursorPosition - // - OriginalCursorPosition -
// - NumberOfVisibleChars // - NumberOfVisibleChars
// - CtrlWakeupMask - Special client parameter to interrupt editing, end the wait, and return control to the client application // - CtrlWakeupMask - Special client parameter to interrupt editing, end the wait, and return control to the client application
// - CommandHistory -
// - Echo - // - Echo -
// - InsertMode - // - InsertMode -
// - Processed - // - Processed -
// - Line - // - Line -
// - pTempHandle - A handle to the output buffer to prevent it from being destroyed while we're using it to present 'edit line' text. // - pTempHandle - A handle to the output buffer to prevent it from being destroyed while we're using it to present 'edit line' text.
// - initialData - any text data that should be prepopulated into the buffer // - initialData - any text data that should be prepopulated into the buffer
// - pClientProcess - Attached process handle object
// Return Value: // Return Value:
// - THROW: Throws E_INVALIDARG for invalid pointers. // - THROW: Throws E_INVALIDARG for invalid pointers.
COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer, COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
@ -49,9 +49,9 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
_In_ size_t UserBufferSize, _In_ size_t UserBufferSize,
_In_ PWCHAR UserBuffer, _In_ PWCHAR UserBuffer,
_In_ ULONG CtrlWakeupMask, _In_ ULONG CtrlWakeupMask,
_In_ CommandHistory* CommandHistory, _In_ const std::wstring_view exeName,
const std::wstring_view exeName, _In_ const std::string_view initialData,
const std::string_view initialData) : _In_ ConsoleProcessHandle* const pClientProcess) :
ReadData(pInputBuffer, pInputReadHandleData), ReadData(pInputBuffer, pInputReadHandleData),
_screenInfo{ screenInfo }, _screenInfo{ screenInfo },
_bytesRead{ 0 }, _bytesRead{ 0 },
@ -62,7 +62,7 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
_exeName{ exeName }, _exeName{ exeName },
_pdwNumBytes{ nullptr }, _pdwNumBytes{ nullptr },
_commandHistory{ CommandHistory }, _commandHistory{ CommandHistory::s_Find((HANDLE)pClientProcess) },
_controlKeyState{ 0 }, _controlKeyState{ 0 },
_ctrlWakeupMask{ CtrlWakeupMask }, _ctrlWakeupMask{ CtrlWakeupMask },
_visibleCharCount{ 0 }, _visibleCharCount{ 0 },
@ -73,7 +73,8 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
_lineInput{ WI_IsFlagSet(pInputBuffer->InputMode, ENABLE_LINE_INPUT) }, _lineInput{ WI_IsFlagSet(pInputBuffer->InputMode, ENABLE_LINE_INPUT) },
_processedInput{ WI_IsFlagSet(pInputBuffer->InputMode, ENABLE_PROCESSED_INPUT) }, _processedInput{ WI_IsFlagSet(pInputBuffer->InputMode, ENABLE_PROCESSED_INPUT) },
_insertMode{ ServiceLocator::LocateGlobals().getConsoleInformation().GetInsertMode() }, _insertMode{ ServiceLocator::LocateGlobals().getConsoleInformation().GetInsertMode() },
_unicode{ false } _unicode{ false },
_clientProcess{ pClientProcess }
{ {
#ifndef UNIT_TESTING #ifndef UNIT_TESTING
THROW_IF_FAILED(screenInfo.GetMainBuffer().AllocateIoHandle(ConsoleHandleData::HandleType::Output, THROW_IF_FAILED(screenInfo.GetMainBuffer().AllocateIoHandle(ConsoleHandleData::HandleType::Output,
@ -1008,13 +1009,13 @@ void COOKED_READ_DATA::SavePendingInput(const size_t index, const bool multiline
{ {
// Figure out where real string ends (at carriage return or end of buffer). // Figure out where real string ends (at carriage return or end of buffer).
PWCHAR StringPtr = _backupLimit; PWCHAR StringPtr = _backupLimit;
size_t StringLength = _bytesRead; size_t StringLength = _bytesRead / sizeof(WCHAR);
bool FoundCR = false; bool FoundCR = false;
for (size_t i = 0; i < (_bytesRead / sizeof(WCHAR)); i++) for (size_t i = 0; i < StringLength; i++)
{ {
if (*StringPtr++ == UNICODE_CARRIAGERETURN) if (*StringPtr++ == UNICODE_CARRIAGERETURN)
{ {
StringLength = i * sizeof(WCHAR); StringLength = i;
FoundCR = true; FoundCR = true;
break; break;
} }
@ -1026,11 +1027,13 @@ void COOKED_READ_DATA::SavePendingInput(const size_t index, const bool multiline
{ {
// add to command line recall list if we have a history list. // add to command line recall list if we have a history list.
CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LOG_IF_FAILED(_commandHistory->Add({ _backupLimit, StringLength / sizeof(wchar_t) }, LOG_IF_FAILED(_commandHistory->Add({ _backupLimit, StringLength },
WI_IsFlagSet(gci.Flags, CONSOLE_HISTORY_NODUP))); WI_IsFlagSet(gci.Flags, CONSOLE_HISTORY_NODUP)));
} }
Tracing::s_TraceCookedRead(_backupLimit); Tracing::s_TraceCookedRead(_clientProcess,
_backupLimit,
base::saturated_cast<ULONG>(StringLength));
// check for alias // check for alias
ProcessAliases(LineCount); ProcessAliases(LineCount);

View file

@ -39,9 +39,9 @@ public:
_In_ size_t UserBufferSize, _In_ size_t UserBufferSize,
_In_ PWCHAR UserBuffer, _In_ PWCHAR UserBuffer,
_In_ ULONG CtrlWakeupMask, _In_ ULONG CtrlWakeupMask,
_In_ CommandHistory* CommandHistory, _In_ const std::wstring_view exeName,
const std::wstring_view exeName, _In_ const std::string_view initialData,
const std::string_view initialData); _In_ ConsoleProcessHandle* const pClientProcess);
~COOKED_READ_DATA() override; ~COOKED_READ_DATA() override;
COOKED_READ_DATA(COOKED_READ_DATA&&) = default; COOKED_READ_DATA(COOKED_READ_DATA&&) = default;
@ -156,6 +156,8 @@ private:
bool _insertMode; bool _insertMode;
bool _unicode; bool _unicode;
ConsoleProcessHandle* const _clientProcess;
[[nodiscard]] NTSTATUS _readCharInputLoop(const bool isUnicode, size_t& numBytes) noexcept; [[nodiscard]] NTSTATUS _readCharInputLoop(const bool isUnicode, size_t& numBytes) noexcept;
[[nodiscard]] NTSTATUS _handlePostCharInputLoop(const bool isUnicode, size_t& numBytes, ULONG& controlKeyState) noexcept; [[nodiscard]] NTSTATUS _handlePostCharInputLoop(const bool isUnicode, size_t& numBytes, ULONG& controlKeyState) noexcept;

View file

@ -310,7 +310,7 @@ void Registry::LoadFromRegistry(_In_ PCWSTR const pwszConsoleTitle)
nullptr); nullptr);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
_pSettings->SetColorTableEntry(i, dwValue); _pSettings->SetLegacyColorTableEntry(i, dwValue);
} }
} }

View file

@ -110,6 +110,8 @@ void RenderData::UnlockConsole() noexcept
const TextAttribute RenderData::GetDefaultBrushColors() noexcept const TextAttribute RenderData::GetDefaultBrushColors() noexcept
{ {
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
_defaultForeground = gci.GetDefaultForeground();
_defaultBackground = gci.GetDefaultBackground();
return gci.GetActiveOutputBuffer().GetAttributes(); return gci.GetActiveOutputBuffer().GetAttributes();
} }
@ -362,7 +364,7 @@ const std::vector<size_t> RenderData::GetPatternId(const COORD /*location*/) con
std::pair<COLORREF, COLORREF> RenderData::GetAttributeColors(const TextAttribute& attr) const noexcept std::pair<COLORREF, COLORREF> RenderData::GetAttributeColors(const TextAttribute& attr) const noexcept
{ {
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
return gci.LookupAttributeColors(attr); return gci.LookupAttributeColors(attr, _defaultForeground, _defaultBackground);
} }
#pragma endregion #pragma endregion

Some files were not shown because too many files have changed in this diff Show more