Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/honk
This commit is contained in:
commit
2eda14cc1b
19
.github/ISSUE_TEMPLATE/Bug_Report.yml
vendored
19
.github/ISSUE_TEMPLATE/Bug_Report.yml
vendored
|
@ -10,14 +10,21 @@ body:
|
|||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Windows Terminal version (or Windows build number)
|
||||
placeholder: "10.0.19042.0, 1.7.3651.0"
|
||||
label: Windows Terminal version
|
||||
placeholder: "1.7.3651.0"
|
||||
description: |
|
||||
If you are reporting an issue in Windows Terminal, you can find the version in the about dialog.
|
||||
|
||||
If you are reporting an issue with the Windows Console, please run `ver` or `[Environment]::OSVersion`.
|
||||
You can find the version in the about dialog, or by running `wt -v` at the commandline.
|
||||
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
|
||||
attributes:
|
||||
|
|
13
.github/actions/spelling/allow/allow.txt
vendored
13
.github/actions/spelling/allow/allow.txt
vendored
|
@ -1,12 +1,14 @@
|
|||
admins
|
||||
apc
|
||||
Apc
|
||||
bsd
|
||||
calt
|
||||
ccmp
|
||||
changelog
|
||||
cybersecurity
|
||||
Apc
|
||||
clickable
|
||||
clig
|
||||
copyable
|
||||
cybersecurity
|
||||
dalet
|
||||
dcs
|
||||
Dcs
|
||||
|
@ -34,16 +36,17 @@ It'd
|
|||
kje
|
||||
liga
|
||||
lje
|
||||
locl
|
||||
lorem
|
||||
Llast
|
||||
Lmid
|
||||
locl
|
||||
lorem
|
||||
Lorigin
|
||||
maxed
|
||||
mkmk
|
||||
mnt
|
||||
mru
|
||||
noreply
|
||||
nje
|
||||
noreply
|
||||
ogonek
|
||||
ok'd
|
||||
overlined
|
||||
|
|
11
.github/actions/spelling/allow/apis.txt
vendored
11
.github/actions/spelling/allow/apis.txt
vendored
|
@ -1,5 +1,7 @@
|
|||
ACCEPTFILES
|
||||
ACCESSDENIED
|
||||
acl
|
||||
aclapi
|
||||
alignas
|
||||
alignof
|
||||
APPLYTOSUBMENUS
|
||||
|
@ -9,6 +11,7 @@ BUILDBRANCH
|
|||
BUILDMSG
|
||||
BUILDNUMBER
|
||||
BYPOSITION
|
||||
BYCOMMAND
|
||||
charconv
|
||||
CLASSNOTAVAILABLE
|
||||
cmdletbinding
|
||||
|
@ -16,9 +19,11 @@ COLORPROPERTY
|
|||
colspan
|
||||
COMDLG
|
||||
comparand
|
||||
commandlinetoargv
|
||||
cstdint
|
||||
CXICON
|
||||
CYICON
|
||||
Dacl
|
||||
dataobject
|
||||
dcomp
|
||||
DERR
|
||||
|
@ -85,6 +90,7 @@ LSHIFT
|
|||
MENUCOMMAND
|
||||
MENUDATA
|
||||
MENUINFO
|
||||
MENUITEMINFOW
|
||||
memicmp
|
||||
mptt
|
||||
mov
|
||||
|
@ -114,15 +120,19 @@ OSVERSIONINFOEXW
|
|||
otms
|
||||
OUTLINETEXTMETRICW
|
||||
overridable
|
||||
PACL
|
||||
PAGESCROLL
|
||||
PEXPLICIT
|
||||
PICKFOLDERS
|
||||
pmr
|
||||
ptstr
|
||||
rcx
|
||||
REGCLS
|
||||
RETURNCMD
|
||||
rfind
|
||||
roundf
|
||||
RSHIFT
|
||||
SACL
|
||||
schandle
|
||||
semver
|
||||
serializer
|
||||
|
@ -159,6 +169,7 @@ toupper
|
|||
TTask
|
||||
TVal
|
||||
UChar
|
||||
ULARGE
|
||||
UPDATEINIFILE
|
||||
userenv
|
||||
wcsstr
|
||||
|
|
1
.github/actions/spelling/allow/names.txt
vendored
1
.github/actions/spelling/allow/names.txt
vendored
|
@ -9,6 +9,7 @@ Diviness
|
|||
dsafa
|
||||
duhowett
|
||||
ekg
|
||||
eryksun
|
||||
ethanschoonover
|
||||
Firefox
|
||||
Gatta
|
||||
|
|
1
.github/actions/spelling/excludes.txt
vendored
1
.github/actions/spelling/excludes.txt
vendored
|
@ -61,6 +61,7 @@ SUMS$
|
|||
^src/host/runft\.bat$
|
||||
^src/host/runut\.bat$
|
||||
^src/interactivity/onecore/BgfxEngine\.
|
||||
^src/renderer/atlas/
|
||||
^src/renderer/wddmcon/WddmConRenderer\.
|
||||
^src/terminal/adapter/ut_adapter/run\.bat$
|
||||
^src/terminal/parser/delfuzzpayload\.bat$
|
||||
|
|
|
@ -400,6 +400,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsTerminal.UIA.Tests",
|
|||
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}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererAtlas", "src\renderer\atlas\atlas.vcxproj", "{8222900C-8B6C-452A-91AC-BE95DB04B95F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x86.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -3438,6 +3480,7 @@ Global
|
|||
{C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {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}
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F} = {05500DEF-2294-41E3-AF9A-24E580B82836}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}
|
||||
|
|
|
@ -214,7 +214,7 @@ resources useful and interesting:
|
|||
* Windows Terminal Launch: [Build 2019
|
||||
Session](https://www.youtube.com/watch?v=KMudkRcwjCw)
|
||||
* 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
|
||||
on the Windows
|
||||
Terminal](http://azuredevopspodcast.clear-measure.com/kayla-cinnamon-and-rich-turner-on-devops-on-the-windows-terminal-team-episode-54)
|
||||
|
|
|
@ -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.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"trimPaste": {
|
||||
"default": true,
|
||||
"description": "When enabled, the Terminal will automatically trim trailing whitespace characters when pasting text",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.detectURLs": {
|
||||
"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.",
|
||||
|
|
|
@ -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
|
||||
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
|
||||
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
|
||||
|
|
|
@ -12,8 +12,30 @@ static_assert(alignof(TextAttribute) == 2);
|
|||
// Ensure that we can memcpy() and memmove() the struct for performance.
|
||||
static_assert(std::is_trivially_copyable_v<TextAttribute>);
|
||||
|
||||
BYTE TextAttribute::s_legacyDefaultForeground = 7;
|
||||
BYTE TextAttribute::s_legacyDefaultBackground = 0;
|
||||
namespace
|
||||
{
|
||||
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:
|
||||
// - Sets the legacy attributes which map to and from the default colors.
|
||||
|
@ -23,8 +45,22 @@ BYTE TextAttribute::s_legacyDefaultBackground = 0;
|
|||
// - None
|
||||
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_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:
|
||||
|
@ -55,13 +91,13 @@ TextAttribute TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(const Te
|
|||
const auto bg{ attribute.GetBackground() };
|
||||
auto copy{ attribute };
|
||||
if (fg.IsIndex16() &&
|
||||
attribute.IsBold() == WI_IsFlagSet(s_legacyDefaultForeground, FOREGROUND_INTENSITY) &&
|
||||
fg.GetIndex() == (s_legacyDefaultForeground & ~FOREGROUND_INTENSITY))
|
||||
attribute.IsBold() == WI_IsFlagSet(s_ansiDefaultForeground, 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.
|
||||
copy.SetDefaultForeground();
|
||||
}
|
||||
if (bg.IsIndex16() && bg.GetIndex() == s_legacyDefaultBackground)
|
||||
if (bg.IsIndex16() && bg.GetIndex() == s_ansiDefaultBackground)
|
||||
{
|
||||
copy.SetDefaultBackground();
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ public:
|
|||
|
||||
explicit constexpr TextAttribute(const WORD wLegacyAttr) noexcept :
|
||||
_wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) },
|
||||
_foreground{ s_LegacyIndexOrDefault(wLegacyAttr & FG_ATTRS, s_legacyDefaultForeground) },
|
||||
_background{ s_LegacyIndexOrDefault((wLegacyAttr & BG_ATTRS) >> 4, s_legacyDefaultBackground) },
|
||||
_foreground{ gsl::at(s_legacyForegroundColorMap, wLegacyAttr & FG_ATTRS) },
|
||||
_background{ gsl::at(s_legacyBackgroundColorMap, (wLegacyAttr & BG_ATTRS) >> 4) },
|
||||
_extendedAttrs{ ExtendedAttributes::Normal },
|
||||
_hyperlinkId{ 0 }
|
||||
{
|
||||
|
@ -167,13 +167,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
static constexpr TextColor s_LegacyIndexOrDefault(const BYTE requestedIndex, const BYTE defaultIndex)
|
||||
{
|
||||
return requestedIndex == defaultIndex ? TextColor{} : TextColor{ requestedIndex, true };
|
||||
}
|
||||
|
||||
static BYTE s_legacyDefaultForeground;
|
||||
static BYTE s_legacyDefaultBackground;
|
||||
static std::array<TextColor, 16> s_legacyForegroundColorMap;
|
||||
static std::array<TextColor, 16> s_legacyBackgroundColorMap;
|
||||
|
||||
uint16_t _wAttrLegacy; // sizeof: 2, alignof: 2
|
||||
uint16_t _hyperlinkId; // sizeof: 2, alignof: 2
|
||||
|
|
|
@ -32,7 +32,7 @@ constexpr std::array<BYTE, 256> CompressedRgbToIndex16 = {
|
|||
// A table mapping indexed colors from the 256-color palette,
|
||||
// down to one of the 16 colors in the legacy palette.
|
||||
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,
|
||||
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,
|
||||
|
@ -252,11 +252,7 @@ BYTE TextColor::GetLegacyIndex(const BYTE defaultIndex) const noexcept
|
|||
{
|
||||
return defaultIndex;
|
||||
}
|
||||
else if (IsIndex16())
|
||||
{
|
||||
return GetIndex();
|
||||
}
|
||||
else if (IsIndex256())
|
||||
else if (IsIndex16() || IsIndex256())
|
||||
{
|
||||
return til::at(Index256ToIndex16, GetIndex());
|
||||
}
|
||||
|
|
|
@ -48,6 +48,23 @@ enum class ColorType : BYTE
|
|||
struct TextColor
|
||||
{
|
||||
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 :
|
||||
_meta{ ColorType::IsDefault },
|
||||
_red{ 0 },
|
||||
|
@ -96,6 +113,16 @@ public:
|
|||
|
||||
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:
|
||||
union
|
||||
{
|
||||
|
|
|
@ -237,7 +237,7 @@ void TextAttributeTests::TestRoundtripDefaultColors()
|
|||
Log::Comment(L"Foreground legacy default index should map to default text color.");
|
||||
legacyAttribute = fgLegacyDefault | BACKGROUND_GREEN;
|
||||
textAttribute.SetDefaultForeground();
|
||||
textAttribute.SetIndexedBackground256(BACKGROUND_GREEN >> 4);
|
||||
textAttribute.SetIndexedBackground256(TextColor::DARK_GREEN);
|
||||
VERIFY_ARE_EQUAL(textAttribute, TextAttribute{ legacyAttribute });
|
||||
|
||||
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.");
|
||||
legacyAttribute = FOREGROUND_GREEN | bgLegacyDefault;
|
||||
textAttribute.SetIndexedForeground256(FOREGROUND_GREEN);
|
||||
textAttribute.SetIndexedForeground256(TextColor::DARK_GREEN);
|
||||
textAttribute.SetDefaultBackground();
|
||||
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, false));
|
||||
|
||||
attr.SetIndexedForeground(0);
|
||||
attr.SetIndexedForeground(TextColor::DARK_BLACK);
|
||||
VERIFY_IS_TRUE(attr.IsBold());
|
||||
|
||||
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");
|
||||
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());
|
||||
|
||||
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");
|
||||
attr.SetBold(true);
|
||||
attr.SetIndexedForeground(8);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_BLACK);
|
||||
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, false));
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace SettingsModelLocalTests
|
|||
|
||||
std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
|
||||
const auto campbellSpan = gsl::make_span(expectedCampbellTable);
|
||||
Utils::InitializeCampbellColorTable(campbellSpan);
|
||||
Utils::InitializeColorTable(campbellSpan);
|
||||
Utils::SetColorTableAlpha(campbellSpan, 0);
|
||||
|
||||
for (size_t i = 0; i < expectedCampbellTable.size(); i++)
|
||||
|
|
|
@ -508,7 +508,7 @@ namespace TerminalAppLocalTests
|
|||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
|
||||
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());
|
||||
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"));
|
||||
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());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
|
@ -844,7 +844,7 @@ namespace TerminalAppLocalTests
|
|||
// | 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();
|
||||
});
|
||||
Sleep(250);
|
||||
|
@ -862,7 +862,7 @@ namespace TerminalAppLocalTests
|
|||
// | 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));
|
||||
// Split again to make the 3rd tab
|
||||
thirdId = tab->_activePane->Id().value();
|
||||
|
@ -882,7 +882,7 @@ namespace TerminalAppLocalTests
|
|||
// | 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));
|
||||
fourthId = tab->_activePane->Id().value();
|
||||
});
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
<ProjectReference Include="$(SolutionDir)src\types\lib\types.vcxproj">
|
||||
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
|
||||
</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">
|
||||
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
|
||||
</ProjectReference>
|
||||
|
|
|
@ -174,10 +174,9 @@ namespace winrt::TerminalApp::implementation
|
|||
else if (const auto& realArgs = args.ActionArgs().try_as<SplitPaneArgs>())
|
||||
{
|
||||
_SplitPane(realArgs.SplitDirection(),
|
||||
realArgs.SplitMode(),
|
||||
// This is safe, we're already filtering so the value is (0, 1)
|
||||
::base::saturated_cast<float>(realArgs.SplitSize()),
|
||||
realArgs.TerminalArgs());
|
||||
_MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <WtExeUtils.h>
|
||||
#include <wil/token_helpers.h >
|
||||
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
using namespace winrt::Windows::ApplicationModel;
|
||||
using namespace winrt::Windows::ApplicationModel::DataTransfer;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
@ -131,38 +133,6 @@ static Documents::Run _BuildErrorRun(const winrt::hstring& text, const ResourceD
|
|||
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
|
||||
{
|
||||
// Function Description:
|
||||
|
@ -214,7 +184,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// The TerminalPage has to be constructed during our construction, to
|
||||
// make sure that there's a terminal page for callers of
|
||||
// SetTitleBarContent
|
||||
_isElevated = _isUserAdmin();
|
||||
_isElevated = ::Microsoft::Console::Utils::IsElevated();
|
||||
_root = winrt::make_self<TerminalPage>();
|
||||
|
||||
_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();
|
||||
_ApplyStartupTaskStateChange();
|
||||
|
||||
auto args = winrt::make_self<SystemMenuChangeArgs>(RS_(L"SettingsMenuItem"), SystemMenuChangeAction::Add, SystemMenuItemHandler(this, &AppLogic::_OpenSettingsUI));
|
||||
_SystemMenuChangeRequestedHandlers(*this, *args);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"AppCreated",
|
||||
|
@ -907,8 +880,6 @@ namespace winrt::TerminalApp::implementation
|
|||
void AppLogic::_RegisterSettingsChange()
|
||||
{
|
||||
const std::filesystem::path settingsPath{ std::wstring_view{ CascadiaSettings::SettingsPath() } };
|
||||
const std::filesystem::path statePath{ std::wstring_view{ ApplicationState::SharedInstance().FilePath() } };
|
||||
|
||||
_reader.create(
|
||||
settingsPath.parent_path().c_str(),
|
||||
false,
|
||||
|
@ -917,14 +888,29 @@ namespace winrt::TerminalApp::implementation
|
|||
// editors, who will write a temp file, then rename it to be the
|
||||
// actual file you wrote. So listen for that too.
|
||||
wil::FolderChangeEvents::FileName | wil::FolderChangeEvents::LastWriteTime,
|
||||
[this, settingsBasename = settingsPath.filename(), stateBasename = statePath.filename()](wil::FolderChangeEvent, PCWSTR fileModified) {
|
||||
const auto modifiedBasename = std::filesystem::path{ fileModified }.filename();
|
||||
[this, settingsBasename = settingsPath.filename()](wil::FolderChangeEvent, PCWSTR fileModified) {
|
||||
// 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)
|
||||
{
|
||||
_reloadSettings->Run();
|
||||
}
|
||||
else if (modifiedBasename == stateBasename)
|
||||
else if (ApplicationState::SharedInstance().IsStatePath(modifiedBasename))
|
||||
{
|
||||
_reloadState();
|
||||
}
|
||||
|
@ -1051,6 +1037,11 @@ namespace winrt::TerminalApp::implementation
|
|||
_SettingsChangedHandlers(*this, nullptr);
|
||||
}
|
||||
|
||||
void AppLogic::_OpenSettingsUI()
|
||||
{
|
||||
_root->OpenSettingsUI();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns a pointer to the global shared settings.
|
||||
[[nodiscard]] CascadiaSettings AppLogic::GetSettings() const noexcept
|
||||
|
@ -1557,6 +1548,11 @@ namespace winrt::TerminalApp::implementation
|
|||
return _root->IsQuakeWindow();
|
||||
}
|
||||
|
||||
void AppLogic::RequestExitFullscreen()
|
||||
{
|
||||
_root->SetFullscreen(false);
|
||||
}
|
||||
|
||||
bool AppLogic::GetMinimizeToNotificationArea()
|
||||
{
|
||||
if constexpr (Feature_NotificationIcon::IsEnabled())
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "AppLogic.g.h"
|
||||
#include "FindTargetWindowResult.g.h"
|
||||
#include "SystemMenuChangeArgs.g.h"
|
||||
#include "Jumplist.h"
|
||||
#include "LanguageProfileNotifier.h"
|
||||
#include "TerminalPage.h"
|
||||
|
@ -35,6 +36,17 @@ namespace winrt::TerminalApp::implementation
|
|||
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>
|
||||
{
|
||||
public:
|
||||
|
@ -79,6 +91,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void SetPersistedLayoutIdx(const uint32_t idx);
|
||||
void SetNumberOfOpenWindows(const uint64_t num);
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
void RequestExitFullscreen();
|
||||
|
||||
Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi);
|
||||
bool CenterOnLaunch();
|
||||
|
@ -113,6 +126,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// -------------------------------- WinRT Events ---------------------------------
|
||||
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(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
|
||||
|
||||
private:
|
||||
bool _isUwp{ false };
|
||||
|
@ -163,6 +177,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void _RegisterSettingsChange();
|
||||
fire_and_forget _DispatchReloadSettings();
|
||||
void _ReloadSettings();
|
||||
void _OpenSettingsUI();
|
||||
|
||||
void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme);
|
||||
|
||||
|
|
|
@ -19,6 +19,20 @@ namespace TerminalApp
|
|||
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
|
||||
{
|
||||
AppLogic();
|
||||
|
@ -60,6 +74,7 @@ namespace TerminalApp
|
|||
void SetPersistedLayoutIdx(UInt32 idx);
|
||||
void SetNumberOfOpenWindows(UInt64 num);
|
||||
void RenameFailed();
|
||||
void RequestExitFullscreen();
|
||||
Boolean IsQuakeWindow();
|
||||
|
||||
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> OpenSystemMenu;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2388,35 +2388,32 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Split the focused pane in our tree of panes, and place the given
|
||||
// TermControl into the newly created pane. If we're the focused pane, then
|
||||
// we'll create two new children, and place them side-by-side in our Grid.
|
||||
// - The same as above, except this takes in the pane directly instead of a
|
||||
// profile and control to make a pane with
|
||||
// Arguments:
|
||||
// - splitType: what type of split we want to create.
|
||||
// - profile: The profile to associate with the newly created pane.
|
||||
// - control: A TermControl to use in the new pane.
|
||||
// - splitSize: the desired size of the split
|
||||
// - newPane: the new pane
|
||||
// Return Value:
|
||||
// - The two newly created Panes, with the original pane first
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitDirection splitType,
|
||||
const float splitSize,
|
||||
const Profile& profile,
|
||||
const TermControl& control)
|
||||
std::shared_ptr<Pane> newPane)
|
||||
{
|
||||
if (!_lastActive)
|
||||
{
|
||||
if (_firstChild && _firstChild->_HasFocusedChild())
|
||||
{
|
||||
return _firstChild->Split(splitType, splitSize, profile, control);
|
||||
return _firstChild->Split(splitType, splitSize, newPane);
|
||||
}
|
||||
else if (_secondChild && _secondChild->_HasFocusedChild())
|
||||
{
|
||||
return _secondChild->Split(splitType, splitSize, profile, control);
|
||||
return _secondChild->Split(splitType, splitSize, newPane);
|
||||
}
|
||||
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
|
||||
auto newPane = std::make_shared<Pane>(profile, control);
|
||||
return _Split(splitType, splitSize, newPane);
|
||||
}
|
||||
|
||||
|
|
|
@ -110,8 +110,7 @@ public:
|
|||
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
|
||||
const float splitSize,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
||||
const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
std::shared_ptr<Pane> pane);
|
||||
bool ToggleSplitOrientation();
|
||||
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateAutoSplit(const std::shared_ptr<Pane> target,
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace winrt::TerminalApp::implementation
|
|||
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
|
||||
|
||||
_CreateNewTabWithProfileAndSettings(profile, settings, existingConnection);
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, existingConnection));
|
||||
|
||||
const uint32_t tabCount = _tabs.Size();
|
||||
const bool usedManualProfile = (newTerminalArgs != nullptr) &&
|
||||
|
@ -244,58 +244,6 @@ namespace winrt::TerminalApp::implementation
|
|||
_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:
|
||||
// - Get the icon of the currently focused terminal control, and set its
|
||||
// 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
|
||||
// current control's live settings (which will include changes
|
||||
// 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.
|
||||
profile = GetClosestProfileForDuplicationOfProfile(profile);
|
||||
const auto settingsCreateResult{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
|
||||
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
if (auto newTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
settingsCreateResult.DefaultSettings().StartingDirectory(workingDirectory);
|
||||
}
|
||||
|
||||
_CreateNewTabWithProfileAndSettings(profile, settingsCreateResult);
|
||||
|
||||
const auto runtimeTabText{ tab.GetTabText() };
|
||||
if (!runtimeTabText.empty())
|
||||
{
|
||||
if (auto newTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
newTab->SetTabText(runtimeTabText);
|
||||
}
|
||||
newTab->SetTabText(runtimeTabText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +336,7 @@ namespace winrt::TerminalApp::implementation
|
|||
try
|
||||
{
|
||||
_SetFocusedTab(tab);
|
||||
_SplitPane(tab, SplitDirection::Automatic, SplitType::Duplicate);
|
||||
_SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
|
|
@ -300,10 +300,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// - true if the ApplicationState should be used.
|
||||
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() &&
|
||||
!IsElevated() &&
|
||||
settings.GlobalSettings().FirstWindowPreference() == FirstWindowPreference::PersistedWindowLayout;
|
||||
}
|
||||
|
||||
|
@ -850,14 +847,7 @@ namespace winrt::TerminalApp::implementation
|
|||
WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
|
||||
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
|
||||
|
||||
if (altPressed && !debugTap)
|
||||
{
|
||||
this->_SplitPane(SplitDirection::Automatic,
|
||||
SplitType::Manual,
|
||||
0.5f,
|
||||
newTerminalArgs);
|
||||
}
|
||||
else if (shiftPressed && !debugTap)
|
||||
if (shiftPressed && !debugTap)
|
||||
{
|
||||
// Manually fill in the evaluated profile.
|
||||
if (newTerminalArgs.ProfileIndex() != nullptr)
|
||||
|
@ -873,7 +863,17 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
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:
|
||||
// - 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:
|
||||
// - newPane: the pane to add to our tree of panes
|
||||
// - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the
|
||||
// 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.
|
||||
// - 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.
|
||||
// - splitSize: the size of the split
|
||||
void TerminalPage::_SplitPane(const SplitDirection splitDirection,
|
||||
const SplitType splitMode,
|
||||
const float splitSize,
|
||||
const NewTerminalArgs& newTerminalArgs)
|
||||
std::shared_ptr<Pane> newPane)
|
||||
{
|
||||
const auto focusedTab{ _GetFocusedTabImpl() };
|
||||
|
||||
|
@ -1506,104 +1503,52 @@ namespace winrt::TerminalApp::implementation
|
|||
return;
|
||||
}
|
||||
|
||||
_SplitPane(*focusedTab, splitDirection, splitMode, splitSize, newTerminalArgs);
|
||||
_SplitPane(*focusedTab, splitDirection, splitSize, newPane);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - 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:
|
||||
// - 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
|
||||
// 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.
|
||||
// - 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.
|
||||
// - splitSize: the size of the split
|
||||
void TerminalPage::_SplitPane(TerminalTab& tab,
|
||||
const SplitDirection splitDirection,
|
||||
const SplitType splitMode,
|
||||
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 };
|
||||
Profile profile{ nullptr };
|
||||
realSplitType = tab.PreCalculateAutoSplit(availableSpace);
|
||||
}
|
||||
|
||||
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();
|
||||
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);
|
||||
}
|
||||
control.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -2111,7 +2056,7 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
if (target == SettingsTarget::SettingsUI)
|
||||
{
|
||||
_OpenSettingsUI();
|
||||
OpenSettingsUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2188,6 +2133,96 @@ namespace winrt::TerminalApp::implementation
|
|||
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:
|
||||
// - Hook up keybindings, and refresh the UI of the terminal.
|
||||
// This includes update the settings of all the tabs according
|
||||
|
@ -2497,9 +2532,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void TerminalPage::ToggleFullscreen()
|
||||
{
|
||||
_isFullscreen = !_isFullscreen;
|
||||
_UpdateTabView();
|
||||
_FullscreenChangedHandlers(*this, nullptr);
|
||||
SetFullscreen(!_isFullscreen);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -2716,6 +2749,17 @@ namespace winrt::TerminalApp::implementation
|
|||
return _isAlwaysOnTop;
|
||||
}
|
||||
|
||||
void TerminalPage::SetFullscreen(bool newFullscreen)
|
||||
{
|
||||
if (_isFullscreen == newFullscreen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_isFullscreen = newFullscreen;
|
||||
_UpdateTabView();
|
||||
_FullscreenChangedHandlers(*this, nullptr);
|
||||
}
|
||||
|
||||
HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection)
|
||||
{
|
||||
// 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 settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
|
||||
|
||||
_CreateNewTabWithProfileAndSettings(profile, settings, connection);
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, connection));
|
||||
|
||||
// Request a summon of this window to the foreground
|
||||
_SummonWindowRequestedHandlers(*this, nullptr);
|
||||
|
@ -2759,7 +2803,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
// Return Value:
|
||||
// - <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 (!_settingsTab)
|
||||
|
@ -3377,7 +3421,7 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipInteracted", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
|
||||
_OpenSettingsUI();
|
||||
OpenSettingsUI();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -83,6 +83,7 @@ namespace winrt::TerminalApp::implementation
|
|||
bool FocusMode() const;
|
||||
bool Fullscreen() const;
|
||||
bool AlwaysOnTop() const;
|
||||
void SetFullscreen(bool);
|
||||
|
||||
void SetStartupActions(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>& actions);
|
||||
|
||||
|
@ -121,6 +122,8 @@ namespace winrt::TerminalApp::implementation
|
|||
bool IsQuakeWindow() const noexcept;
|
||||
bool IsElevated() const noexcept;
|
||||
|
||||
void OpenSettingsUI();
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
|
@ -209,7 +212,6 @@ namespace winrt::TerminalApp::implementation
|
|||
void _OpenNewTabDropdown();
|
||||
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
|
||||
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::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 _SplitPane(const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
|
||||
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual,
|
||||
const float splitSize = 0.5f,
|
||||
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
|
||||
const float splitSize,
|
||||
std::shared_ptr<Pane> newPane);
|
||||
void _SplitPane(TerminalTab& tab,
|
||||
const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
|
||||
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual,
|
||||
const float splitSize = 0.5f,
|
||||
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
|
||||
const float splitSize,
|
||||
std::shared_ptr<Pane> newPane);
|
||||
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
|
||||
void _ToggleSplitOrientation();
|
||||
|
||||
|
@ -351,6 +351,10 @@ namespace winrt::TerminalApp::implementation
|
|||
winrt::Microsoft::Terminal::Control::TermControl _InitControl(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
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 _SetNonClientAreaColors(const Windows::UI::Color& selectedTabColor);
|
||||
|
@ -366,8 +370,6 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void _UnZoomIfNeeded();
|
||||
|
||||
void _OpenSettingsUI();
|
||||
|
||||
static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll);
|
||||
static uint32_t _ReadSystemRowsToScroll();
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@
|
|||
</ContentDialog>
|
||||
|
||||
<local:CommandPalette x:Name="CommandPalette"
|
||||
Grid.Row="1"
|
||||
Grid.Row="2"
|
||||
VerticalAlignment="Stretch"
|
||||
PreviewKeyDown="_KeyDownHandler"
|
||||
Visibility="Collapsed" />
|
||||
|
|
|
@ -25,18 +25,6 @@ namespace winrt
|
|||
|
||||
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)
|
||||
{
|
||||
_rootPane = rootPane;
|
||||
|
@ -64,8 +52,9 @@ namespace winrt::TerminalApp::implementation
|
|||
// focus the first one.
|
||||
if (_activePane == nullptr)
|
||||
{
|
||||
_rootPane->FocusPane(firstId);
|
||||
_activePane = _rootPane->GetActivePane();
|
||||
const auto firstPane = _rootPane->FindPane(firstId);
|
||||
firstPane->SetActive();
|
||||
_activePane = firstPane;
|
||||
}
|
||||
// If the focused pane is a leaf, add it to the MRU panes
|
||||
if (const auto id = _activePane->Id())
|
||||
|
@ -503,39 +492,48 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
// Method Description:
|
||||
// - 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:
|
||||
// - splitType: The type of split we want to create.
|
||||
// - profile: The profile GUID to associate with the newly created pane.
|
||||
// - control: A TermControl to use in the new pane.
|
||||
// - splitType: The type of split we want to create
|
||||
// - splitSize: The size of the split we want to create
|
||||
// - 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:
|
||||
// - <none>
|
||||
void TerminalTab::SplitPane(SplitDirection splitType,
|
||||
const float splitSize,
|
||||
const Profile& profile,
|
||||
TermControl& control)
|
||||
std::shared_ptr<Pane> pane)
|
||||
{
|
||||
// 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
|
||||
const auto activePaneId = _activePane->Id();
|
||||
// Depending on which direction will be split, the new pane can be
|
||||
// either the first or second child, but this will always return the
|
||||
// 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
|
||||
if (activePaneId)
|
||||
{
|
||||
original->Id(activePaneId.value());
|
||||
}
|
||||
newPane->Id(_nextPaneId);
|
||||
++_nextPaneId;
|
||||
|
||||
_activePane = original;
|
||||
|
||||
// Add a event handlers to the new panes' GotFocus event. When the pane
|
||||
// gains focus, we'll mark it as the new active pane.
|
||||
_AttachEventHandlersToControl(newPane->Id().value(), control);
|
||||
_AttachEventHandlersToPane(original);
|
||||
_AttachEventHandlersToPane(newPane);
|
||||
|
||||
// Immediately update our tracker of the focused pane now. If we're
|
||||
// splitting panes during startup (from a commandline), then it's
|
||||
|
|
|
@ -21,7 +21,6 @@ namespace winrt::TerminalApp::implementation
|
|||
struct TerminalTab : TerminalTabT<TerminalTab, TabBase>
|
||||
{
|
||||
public:
|
||||
TerminalTab(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
TerminalTab(std::shared_ptr<Pane> rootPane);
|
||||
|
||||
// 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,
|
||||
const float splitSize,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
||||
winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
std::shared_ptr<Pane> newPane);
|
||||
|
||||
void ToggleSplitOrientation();
|
||||
winrt::fire_and_forget UpdateIcon(const winrt::hstring iconPath);
|
||||
|
|
|
@ -429,8 +429,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||
// EXIT POINT
|
||||
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") },
|
||||
fmt::format(_errorFormat, hr),
|
||||
fmt::format(_errorFormat, static_cast<unsigned int>(hr)),
|
||||
_commandline) };
|
||||
_TerminalOutputHandlers(failureText);
|
||||
|
||||
|
@ -457,6 +458,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
|||
{
|
||||
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)) };
|
||||
_TerminalOutputHandlers(L"\r\n");
|
||||
_TerminalOutputHandlers(exitText);
|
||||
|
|
|
@ -3,16 +3,18 @@
|
|||
|
||||
#include "pch.h"
|
||||
#include "ControlCore.h"
|
||||
#include <argb.h>
|
||||
|
||||
#include <DefaultSettings.h>
|
||||
#include <unicode.hpp>
|
||||
#include <Utf16Parser.hpp>
|
||||
#include <Utils.h>
|
||||
#include <WinUser.h>
|
||||
#include <LibraryResources.h>
|
||||
|
||||
#include "EventArgs.h"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
#include "../../types/inc/Utils.hpp"
|
||||
#include "../../buffer/out/search.h"
|
||||
#include "../../renderer/atlas/AtlasEngine.h"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
|
||||
#include "ControlCore.g.cpp"
|
||||
|
||||
|
@ -202,6 +204,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
const double actualHeight,
|
||||
const double compositionScale)
|
||||
{
|
||||
assert(_settings);
|
||||
|
||||
_panelWidth = actualWidth;
|
||||
_panelHeight = actualHeight;
|
||||
_compositionScale = compositionScale;
|
||||
|
@ -222,10 +226,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
return false;
|
||||
}
|
||||
|
||||
// Set up the DX Engine
|
||||
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
|
||||
_renderer->AddRenderEngine(dxEngine.get());
|
||||
_renderEngine = std::move(dxEngine);
|
||||
if (Feature_AtlasEngine::IsEnabled() && _settings.UseAtlasEngine())
|
||||
{
|
||||
_renderEngine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
|
||||
}
|
||||
else
|
||||
{
|
||||
_renderEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
|
||||
}
|
||||
|
||||
_renderer->AddRenderEngine(_renderEngine.get());
|
||||
|
||||
// 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
|
||||
|
@ -271,11 +281,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
_renderEngine->SetIntenseIsBold(_settings.IntenseIsBold());
|
||||
|
||||
_updateAntiAliasingMode(_renderEngine.get());
|
||||
_updateAntiAliasingMode();
|
||||
|
||||
// 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.
|
||||
_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());
|
||||
|
||||
|
@ -616,7 +627,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
||||
|
||||
_updateAntiAliasingMode(_renderEngine.get());
|
||||
_updateAntiAliasingMode();
|
||||
|
||||
// Refresh our font with the renderer
|
||||
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())
|
||||
{
|
||||
case TextAntialiasingMode::Cleartype:
|
||||
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
|
||||
mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
||||
break;
|
||||
case TextAntialiasingMode::Aliased:
|
||||
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
|
||||
mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
||||
break;
|
||||
case TextAntialiasingMode::Grayscale:
|
||||
default:
|
||||
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
|
||||
mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
||||
break;
|
||||
}
|
||||
|
||||
_renderEngine->SetAntialiasingMode(mode);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -1296,7 +1309,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
if (_renderEngine)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "EventArgs.h"
|
||||
#include "ControlCore.g.h"
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../renderer/uia/UiaRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../buffer/out/search.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)
|
||||
// we must ensure the _renderer is deallocated first.
|
||||
// (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 };
|
||||
|
||||
IControlSettings _settings{ nullptr };
|
||||
|
@ -248,7 +245,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
#pragma endregion
|
||||
|
||||
void _raiseReadOnlyWarning();
|
||||
void _updateAntiAliasingMode(::Microsoft::Console::Render::DxEngine* const dxEngine);
|
||||
void _updateAntiAliasingMode();
|
||||
void _connectionOutputHandler(const hstring& hstr);
|
||||
void _updateHoveredCell(const std::optional<til::point> terminalPosition);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "cppwinrt_utils.h"
|
||||
|
||||
#include "ControlCore.h"
|
||||
#include "../../renderer/uia/UiaRenderer.hpp"
|
||||
|
||||
namespace ControlUnitTests
|
||||
{
|
||||
|
|
|
@ -27,10 +27,11 @@ namespace Microsoft.Terminal.Control
|
|||
interface IControlSettings requires Microsoft.Terminal.Core.ICoreSettings, Microsoft.Terminal.Control.IControlAppearance
|
||||
{
|
||||
String ProfileName;
|
||||
String ProfileSource;
|
||||
|
||||
Boolean UseAcrylic;
|
||||
ScrollbarState ScrollState;
|
||||
|
||||
Boolean UseAtlasEngine;
|
||||
String FontFace;
|
||||
Int32 FontSize;
|
||||
Windows.UI.Text.FontWeight FontWeight;
|
||||
|
|
|
@ -3,17 +3,16 @@
|
|||
|
||||
#include "pch.h"
|
||||
#include "TermControl.h"
|
||||
#include <argb.h>
|
||||
#include <DefaultSettings.h>
|
||||
|
||||
#include <unicode.hpp>
|
||||
#include <Utf16Parser.hpp>
|
||||
#include <Utils.h>
|
||||
#include <LibraryResources.h>
|
||||
|
||||
#include "TermControlAutomationPeer.h"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
#include "../../types/inc/Utils.hpp"
|
||||
#include "../../renderer/atlas/AtlasEngine.h"
|
||||
|
||||
#include "TermControl.g.cpp"
|
||||
#include "TermControlAutomationPeer.h"
|
||||
|
||||
using namespace ::Microsoft::Console::Types;
|
||||
using namespace ::Microsoft::Console::VirtualTerminal;
|
||||
|
@ -1828,13 +1827,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
const winrt::Windows::Foundation::Size initialSize{ cols, rows };
|
||||
|
||||
return GetProposedDimensions(initialSize,
|
||||
settings.FontSize(),
|
||||
settings.FontWeight(),
|
||||
settings.FontFace(),
|
||||
settings.ScrollState(),
|
||||
settings.Padding(),
|
||||
dpi);
|
||||
return GetProposedDimensions(settings, dpi, initialSize);
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
|
@ -1855,16 +1848,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
// caller knows what monitor the control is about to appear on.
|
||||
// Return Value:
|
||||
// - a size containing the requested dimensions in pixels.
|
||||
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(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)
|
||||
winrt::Windows::Foundation::Size TermControl::GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars)
|
||||
{
|
||||
const auto cols = ::base::saturated_cast<int>(initialSizeInChars.Width);
|
||||
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.
|
||||
// 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
|
||||
// not, but DX doesn't use that info 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 };
|
||||
|
||||
// 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
|
||||
// will take up.
|
||||
// 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
|
||||
// whole app will crash instantaneously on launch, which is no good.
|
||||
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
|
||||
LOG_IF_FAILED(dxEngine->UpdateDpi(dpi));
|
||||
LOG_IF_FAILED(dxEngine->UpdateFont(desiredFont, actualFont));
|
||||
double scale;
|
||||
if (Feature_AtlasEngine::IsEnabled() && settings.UseAtlasEngine())
|
||||
{
|
||||
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 fontSize = actualFont.GetSize();
|
||||
const auto actualFontSize = actualFont.GetSize();
|
||||
|
||||
// UWP XAML scrollbars aren't guaranteed to be the same size as the
|
||||
// ComCtl scrollbars, but it's certainly close enough.
|
||||
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
|
||||
if (scrollState == ScrollbarState::Visible)
|
||||
|
@ -1902,7 +1905,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
width += scrollbarSize;
|
||||
}
|
||||
|
||||
double height = rows * fontSize.Y;
|
||||
double height = rows * actualFontSize.Y;
|
||||
const auto thickness = ParseThicknessFromPadding(padding);
|
||||
// GH#2061 - make sure to account for the size the padding _will be_ scaled to
|
||||
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 double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
|
||||
const auto dpi = ::base::saturated_cast<uint32_t>(USER_DEFAULT_SCREEN_DPI * scaleFactor);
|
||||
return GetProposedDimensions(minSize,
|
||||
_settings.FontSize(),
|
||||
_settings.FontWeight(),
|
||||
_settings.FontFace(),
|
||||
_settings.ScrollState(),
|
||||
_settings.Padding(),
|
||||
dpi);
|
||||
return GetProposedDimensions(_settings, dpi, minSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2271,6 +2268,42 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
}
|
||||
|
||||
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(),
|
||||
fullPath.end(),
|
||||
L' ') != fullPath.end();
|
||||
|
@ -2283,6 +2316,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
|
||||
allPaths += fullPath;
|
||||
}
|
||||
|
||||
_core.PasteText(winrt::hstring{ allPaths });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,13 +92,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
|||
void Settings(IControlSettings newSettings);
|
||||
|
||||
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi);
|
||||
static Windows::Foundation::Size GetProposedDimensions(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);
|
||||
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars);
|
||||
|
||||
void BellLightOn();
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@
|
|||
<ProjectReference Include="..\..\types\lib\types.vcxproj" />
|
||||
<ProjectReference Include="..\..\buffer\out\lib\bufferout.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\uia\lib\uia.vcxproj" />
|
||||
<ProjectReference Include="..\..\terminal\parser\lib\parser.vcxproj" />
|
||||
|
|
|
@ -1210,9 +1210,7 @@ try
|
|||
{
|
||||
const gsl::span<COLORREF> tableView = { _colorTable.data(), _colorTable.size() };
|
||||
// First set up the basic 256 colors
|
||||
Utils::Initialize256ColorTable(tableView);
|
||||
// Then use fill the first 16 values with the Campbell scheme
|
||||
Utils::InitializeCampbellColorTable(tableView);
|
||||
Utils::InitializeColorTable(tableView);
|
||||
// Then make sure all the values have an alpha of 255
|
||||
Utils::SetColorTableAlpha(tableView, 0xff);
|
||||
}
|
||||
|
|
|
@ -7,29 +7,6 @@
|
|||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
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:
|
||||
// - 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)
|
||||
|
@ -169,100 +146,100 @@ bool TerminalDispatch::SetGraphicsRendition(const VTParameters options) noexcept
|
|||
attr.SetOverlined(false);
|
||||
break;
|
||||
case ForegroundBlack:
|
||||
attr.SetIndexedForeground(DARK_BLACK);
|
||||
attr.SetIndexedForeground(TextColor::DARK_BLACK);
|
||||
break;
|
||||
case ForegroundBlue:
|
||||
attr.SetIndexedForeground(DARK_BLUE);
|
||||
attr.SetIndexedForeground(TextColor::DARK_BLUE);
|
||||
break;
|
||||
case ForegroundGreen:
|
||||
attr.SetIndexedForeground(DARK_GREEN);
|
||||
attr.SetIndexedForeground(TextColor::DARK_GREEN);
|
||||
break;
|
||||
case ForegroundCyan:
|
||||
attr.SetIndexedForeground(DARK_CYAN);
|
||||
attr.SetIndexedForeground(TextColor::DARK_CYAN);
|
||||
break;
|
||||
case ForegroundRed:
|
||||
attr.SetIndexedForeground(DARK_RED);
|
||||
attr.SetIndexedForeground(TextColor::DARK_RED);
|
||||
break;
|
||||
case ForegroundMagenta:
|
||||
attr.SetIndexedForeground(DARK_MAGENTA);
|
||||
attr.SetIndexedForeground(TextColor::DARK_MAGENTA);
|
||||
break;
|
||||
case ForegroundYellow:
|
||||
attr.SetIndexedForeground(DARK_YELLOW);
|
||||
attr.SetIndexedForeground(TextColor::DARK_YELLOW);
|
||||
break;
|
||||
case ForegroundWhite:
|
||||
attr.SetIndexedForeground(DARK_WHITE);
|
||||
attr.SetIndexedForeground(TextColor::DARK_WHITE);
|
||||
break;
|
||||
case BackgroundBlack:
|
||||
attr.SetIndexedBackground(DARK_BLACK);
|
||||
attr.SetIndexedBackground(TextColor::DARK_BLACK);
|
||||
break;
|
||||
case BackgroundBlue:
|
||||
attr.SetIndexedBackground(DARK_BLUE);
|
||||
attr.SetIndexedBackground(TextColor::DARK_BLUE);
|
||||
break;
|
||||
case BackgroundGreen:
|
||||
attr.SetIndexedBackground(DARK_GREEN);
|
||||
attr.SetIndexedBackground(TextColor::DARK_GREEN);
|
||||
break;
|
||||
case BackgroundCyan:
|
||||
attr.SetIndexedBackground(DARK_CYAN);
|
||||
attr.SetIndexedBackground(TextColor::DARK_CYAN);
|
||||
break;
|
||||
case BackgroundRed:
|
||||
attr.SetIndexedBackground(DARK_RED);
|
||||
attr.SetIndexedBackground(TextColor::DARK_RED);
|
||||
break;
|
||||
case BackgroundMagenta:
|
||||
attr.SetIndexedBackground(DARK_MAGENTA);
|
||||
attr.SetIndexedBackground(TextColor::DARK_MAGENTA);
|
||||
break;
|
||||
case BackgroundYellow:
|
||||
attr.SetIndexedBackground(DARK_YELLOW);
|
||||
attr.SetIndexedBackground(TextColor::DARK_YELLOW);
|
||||
break;
|
||||
case BackgroundWhite:
|
||||
attr.SetIndexedBackground(DARK_WHITE);
|
||||
attr.SetIndexedBackground(TextColor::DARK_WHITE);
|
||||
break;
|
||||
case BrightForegroundBlack:
|
||||
attr.SetIndexedForeground(BRIGHT_BLACK);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_BLACK);
|
||||
break;
|
||||
case BrightForegroundBlue:
|
||||
attr.SetIndexedForeground(BRIGHT_BLUE);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_BLUE);
|
||||
break;
|
||||
case BrightForegroundGreen:
|
||||
attr.SetIndexedForeground(BRIGHT_GREEN);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_GREEN);
|
||||
break;
|
||||
case BrightForegroundCyan:
|
||||
attr.SetIndexedForeground(BRIGHT_CYAN);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_CYAN);
|
||||
break;
|
||||
case BrightForegroundRed:
|
||||
attr.SetIndexedForeground(BRIGHT_RED);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_RED);
|
||||
break;
|
||||
case BrightForegroundMagenta:
|
||||
attr.SetIndexedForeground(BRIGHT_MAGENTA);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_MAGENTA);
|
||||
break;
|
||||
case BrightForegroundYellow:
|
||||
attr.SetIndexedForeground(BRIGHT_YELLOW);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_YELLOW);
|
||||
break;
|
||||
case BrightForegroundWhite:
|
||||
attr.SetIndexedForeground(BRIGHT_WHITE);
|
||||
attr.SetIndexedForeground(TextColor::BRIGHT_WHITE);
|
||||
break;
|
||||
case BrightBackgroundBlack:
|
||||
attr.SetIndexedBackground(BRIGHT_BLACK);
|
||||
attr.SetIndexedBackground(TextColor::BRIGHT_BLACK);
|
||||
break;
|
||||
case BrightBackgroundBlue:
|
||||
attr.SetIndexedBackground(BRIGHT_BLUE);
|
||||
attr.SetIndexedBackground(TextColor::BRIGHT_BLUE);
|
||||
break;
|
||||
case BrightBackgroundGreen:
|
||||
attr.SetIndexedBackground(BRIGHT_GREEN);
|
||||
attr.SetIndexedBackground(TextColor::BRIGHT_GREEN);
|
||||
break;
|
||||
case BrightBackgroundCyan:
|
||||
attr.SetIndexedBackground(BRIGHT_CYAN);
|
||||
attr.SetIndexedBackground(TextColor::BRIGHT_CYAN);
|
||||
break;
|
||||
case BrightBackgroundRed:
|
||||
attr.SetIndexedBackground(BRIGHT_RED);
|
||||
attr.SetIndexedBackground(TextColor::BRIGHT_RED);
|
||||
break;
|
||||
case BrightBackgroundMagenta:
|
||||
attr.SetIndexedBackground(BRIGHT_MAGENTA);
|
||||
attr.SetIndexedBackground(TextColor::BRIGHT_MAGENTA);
|
||||
break;
|
||||
case BrightBackgroundYellow:
|
||||
attr.SetIndexedBackground(BRIGHT_YELLOW);
|
||||
attr.SetIndexedBackground(TextColor::BRIGHT_YELLOW);
|
||||
break;
|
||||
case BrightBackgroundWhite:
|
||||
attr.SetIndexedBackground(BRIGHT_WHITE);
|
||||
attr.SetIndexedBackground(TextColor::BRIGHT_WHITE);
|
||||
break;
|
||||
case ForegroundExtended:
|
||||
i += _SetRgbColorsHelper(options.subspan(i + 1), attr, true);
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
<ProjectReference Include="$(OpenConsoleDir)src\terminal\parser\lib\parser.vcxproj">
|
||||
<Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project>
|
||||
</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">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
|
||||
</ProjectReference>
|
||||
|
|
|
@ -246,13 +246,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
return _profile.HasUnfocusedAppearance();
|
||||
}
|
||||
|
||||
bool ProfileViewModel::EditableUnfocusedAppearance()
|
||||
bool ProfileViewModel::EditableUnfocusedAppearance() const noexcept
|
||||
{
|
||||
if constexpr (Feature_EditableUnfocusedAppearance::IsEnabled())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return Feature_EditableUnfocusedAppearance::IsEnabled();
|
||||
}
|
||||
|
||||
bool ProfileViewModel::ShowUnfocusedAppearance()
|
||||
|
@ -286,6 +282,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
return _unfocusedAppearanceViewModel;
|
||||
}
|
||||
|
||||
bool ProfileViewModel::AtlasEngineAvailable() const noexcept
|
||||
{
|
||||
return Feature_AtlasEngine::IsEnabled();
|
||||
}
|
||||
|
||||
bool ProfileViewModel::UseParentProcessDirectory()
|
||||
{
|
||||
return StartingDirectory().empty();
|
||||
|
|
|
@ -61,12 +61,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||
Editor::AppearanceViewModel DefaultAppearance();
|
||||
Editor::AppearanceViewModel UnfocusedAppearance();
|
||||
bool HasUnfocusedAppearance();
|
||||
bool EditableUnfocusedAppearance();
|
||||
bool EditableUnfocusedAppearance() const noexcept;
|
||||
bool ShowUnfocusedAppearance();
|
||||
|
||||
void CreateUnfocusedAppearance(const Windows::Foundation::Collections::IMapView<hstring, Model::ColorScheme>& schemes,
|
||||
const IHostedInWindow& windowRoot);
|
||||
void DeleteUnfocusedAppearance();
|
||||
bool AtlasEngineAvailable() const noexcept;
|
||||
|
||||
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, StartingDirectory);
|
||||
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(), Background);
|
||||
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, AltGrAliasing);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, UseAtlasEngine);
|
||||
|
||||
private:
|
||||
Model::Profile _profile;
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||
Boolean EditableUnfocusedAppearance { get; };
|
||||
Boolean ShowUnfocusedAppearance { get; };
|
||||
AppearanceViewModel UnfocusedAppearance { get; };
|
||||
Boolean AtlasEngineAvailable { get; };
|
||||
|
||||
void CreateUnfocusedAppearance(Windows.Foundation.Collections.IMapView<String, Microsoft.Terminal.Settings.Model.ColorScheme> Schemes, IHostedInWindow WindowRoot);
|
||||
void DeleteUnfocusedAppearance();
|
||||
|
@ -53,8 +54,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, Commandline);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, StartingDirectory);
|
||||
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>, Background);
|
||||
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, AltGrAliasing);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAtlasEngine);
|
||||
}
|
||||
|
||||
runtimeclass DeleteProfileEventArgs
|
||||
|
|
|
@ -319,7 +319,7 @@
|
|||
</StackPanel>
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Visibility="{x:Bind State.Profile.EditableUnfocusedAppearance, Mode=OneWay}">
|
||||
Visibility="{x:Bind State.Profile.EditableUnfocusedAppearance}">
|
||||
<TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock"
|
||||
Style="{StaticResource TitleTextBlockStyle}" />
|
||||
<Button x:Uid="Profile_CreateUnfocusedAppearanceButton"
|
||||
|
@ -477,6 +477,15 @@
|
|||
IsChecked="{x:Bind IsBellStyleFlagSet(4), BindBack=SetBellStyleTaskbar, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</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>
|
||||
</ScrollViewer>
|
||||
</PivotItem>
|
||||
|
|
|
@ -927,6 +927,10 @@
|
|||
<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>
|
||||
</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">
|
||||
<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>
|
||||
|
|
|
@ -16,17 +16,6 @@ static constexpr std::string_view ForegroundKey{ "foreground" };
|
|||
static constexpr std::string_view BackgroundKey{ "background" };
|
||||
static constexpr std::string_view SelectionBackgroundKey{ "selectionBackground" };
|
||||
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 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)
|
||||
{
|
||||
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->_Background = source->_Background;
|
||||
appearance->_SelectionBackground = source->_SelectionBackground;
|
||||
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->_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;
|
||||
}
|
||||
|
||||
|
@ -65,19 +49,13 @@ Json::Value AppearanceConfig::ToJson() const
|
|||
JsonUtils::SetValueForKey(json, BackgroundKey, _Background);
|
||||
JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
|
||||
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>{});
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
@ -98,19 +76,14 @@ void AppearanceConfig::LayerJson(const Json::Value& json)
|
|||
JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
|
||||
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
|
||||
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, 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()
|
||||
|
|
|
@ -19,6 +19,7 @@ Author(s):
|
|||
#include "AppearanceConfig.g.h"
|
||||
#include "JsonUtils.h"
|
||||
#include "IInheritable.h"
|
||||
#include "MTSMSettings.h"
|
||||
#include <DefaultSettings.h>
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
@ -35,26 +36,16 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
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, Background, nullptr);
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, SelectionBackground, 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, 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:
|
||||
winrt::weak_ref<Profile> _sourceProfile;
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
#include "ActionAndArgs.h"
|
||||
#include "JsonUtils.h"
|
||||
#include "FileUtils.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
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 InitialPositionKey{ "initialPosition" };
|
||||
static constexpr std::string_view InitialSizeKey{ "initialSize" };
|
||||
|
@ -85,15 +88,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
return trait.FromJson(root);
|
||||
}
|
||||
|
||||
// Returns the application-global ApplicationState object.
|
||||
Microsoft::Terminal::Settings::Model::ApplicationState ApplicationState::SharedInstance()
|
||||
{
|
||||
static auto state = winrt::make_self<ApplicationState>(GetBaseSettingsPath() / stateFileName);
|
||||
return *state;
|
||||
}
|
||||
|
||||
ApplicationState::ApplicationState(std::filesystem::path path) noexcept :
|
||||
_path{ std::move(path) },
|
||||
ApplicationState::ApplicationState(const std::filesystem::path& stateRoot) noexcept :
|
||||
_sharedPath{ stateRoot / stateFileName },
|
||||
_elevatedPath{ stateRoot / elevatedStateFileName },
|
||||
_throttler{ std::chrono::seconds(1), [this]() { _write(); } }
|
||||
{
|
||||
_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.
|
||||
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,
|
||||
// but instead force it to run as soon as possible and wait for it to complete.
|
||||
_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.
|
||||
|
@ -113,34 +122,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
_read();
|
||||
}
|
||||
|
||||
// Returns the state.json path on the disk.
|
||||
winrt::hstring ApplicationState::FilePath() const noexcept
|
||||
bool ApplicationState::IsStatePath(const winrt::hstring& filename)
|
||||
{
|
||||
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:
|
||||
// - 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
|
||||
|
@ -156,57 +144,58 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
void ApplicationState::Reset() noexcept
|
||||
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() = {};
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
Json::Value ApplicationState::_getRoot(const locked_hfile& file) const noexcept
|
||||
{
|
||||
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.
|
||||
// Deserializes the state.json and user-state (or elevated-state if
|
||||
// elevated) into this ApplicationState.
|
||||
// * 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.
|
||||
void ApplicationState::_read() const noexcept
|
||||
try
|
||||
{
|
||||
auto state = _state.lock();
|
||||
const auto file = OpenFileReadSharedLocked(_path);
|
||||
std::string errs;
|
||||
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
|
||||
|
||||
auto root = _getRoot(file);
|
||||
// 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.
|
||||
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
|
||||
if (!state->name##Changed) \
|
||||
{ \
|
||||
state->name = JsonUtils::GetValueForKey<std::optional<type>>(root, key); \
|
||||
}
|
||||
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
|
||||
#undef MTSM_APPLICATION_STATE_GEN
|
||||
// First get shared state out of `state.json`.
|
||||
const auto sharedData = _readSharedContents().value_or(std::string{});
|
||||
if (!sharedData.empty())
|
||||
{
|
||||
Json::Value root;
|
||||
if (!reader->parse(sharedData.data(), sharedData.data() + sharedData.size(), &root, &errs))
|
||||
{
|
||||
throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs));
|
||||
}
|
||||
|
||||
// - If we're elevated, we want to only load the Shared properties
|
||||
// from state.json. We'll then load the Local props from
|
||||
// `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()
|
||||
|
||||
|
@ -214,29 +203,191 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
// * Errors are only logged.
|
||||
// * _state->_writeScheduled is set to false, signaling our
|
||||
// setters that _synchronize() needs to be called again.
|
||||
void ApplicationState::_write() noexcept
|
||||
void ApplicationState::_write() const noexcept
|
||||
try
|
||||
{
|
||||
// re-read the state so that we can only update the properties that were changed.
|
||||
Json::Value root{};
|
||||
Json::StreamWriterBuilder wbuilder;
|
||||
|
||||
// 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();
|
||||
const auto file = OpenFileRWExclusiveLocked(_path);
|
||||
root = _getRoot(file);
|
||||
std::string errs;
|
||||
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
|
||||
Json::Value root;
|
||||
|
||||
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
|
||||
if (state->name##Changed) \
|
||||
{ \
|
||||
JsonUtils::SetValueForKey(root, key, state->name); \
|
||||
state->name##Changed = false; \
|
||||
}
|
||||
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
|
||||
#undef MTSM_APPLICATION_STATE_GEN
|
||||
// First load the contents of state.json into a json blob. This will
|
||||
// contain the Shared properties and the unelevated instance's Local
|
||||
// properties.
|
||||
const auto sharedData = _readSharedContents().value_or(std::string{});
|
||||
if (!sharedData.empty())
|
||||
{
|
||||
if (!reader->parse(sharedData.data(), sharedData.data() + sharedData.size(), &root, &errs))
|
||||
{
|
||||
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;
|
||||
const auto content = Json::writeString(wbuilder, root);
|
||||
WriteUTF8FileLocked(file, content);
|
||||
// Finally, write our Local properties back to elevated-state.json
|
||||
_writeLocalContents(Json::writeString(wbuilder, ToJson(FileSource::Local)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're unelevated, this is easy. Just write everything back out.
|
||||
_writeLocalContents(Json::writeString(wbuilder, ToJson(FileSource::Local | FileSource::Shared)));
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,21 +16,30 @@ Abstract:
|
|||
#include "WindowLayout.g.h"
|
||||
|
||||
#include <inc/cppwinrt_utils.h>
|
||||
#include <til/mutex.h>
|
||||
#include <til/throttled_func.h>
|
||||
#include "FileUtils.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.
|
||||
// It provides X with the following arguments:
|
||||
// (type, function name, JSON key, ...variadic construction arguments)
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
#define MTSM_APPLICATION_STATE_FIELDS(X) \
|
||||
X(std::unordered_set<winrt::guid>, GeneratedProfiles, "generatedProfiles") \
|
||||
X(Windows::Foundation::Collections::IVector<Model::WindowLayout>, PersistedWindowLayouts, "persistedWindowLayouts") \
|
||||
X(Windows::Foundation::Collections::IVector<hstring>, RecentCommands, "recentCommands") \
|
||||
X(Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage>, DismissedMessages, "dismissedMessages")
|
||||
// (source, type, function name, JSON key, ...variadic construction arguments)
|
||||
#define MTSM_APPLICATION_STATE_FIELDS(X) \
|
||||
X(FileSource::Shared, std::unordered_set<winrt::guid>, GeneratedProfiles, "generatedProfiles") \
|
||||
X(FileSource::Local, Windows::Foundation::Collections::IVector<Model::WindowLayout>, PersistedWindowLayouts, "persistedWindowLayouts") \
|
||||
X(FileSource::Shared, Windows::Foundation::Collections::IVector<hstring>, RecentCommands, "recentCommands") \
|
||||
X(FileSource::Shared, Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage>, DismissedMessages, "dismissedMessages") \
|
||||
X(FileSource::Local, Windows::Foundation::Collections::IVector<hstring>, AllowedCommandlines, "allowedCommandlines")
|
||||
|
||||
struct WindowLayout : WindowLayoutT<WindowLayout>
|
||||
{
|
||||
|
@ -44,23 +53,26 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
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();
|
||||
|
||||
ApplicationState(std::filesystem::path path) noexcept;
|
||||
ApplicationState(const std::filesystem::path& stateRoot) noexcept;
|
||||
~ApplicationState();
|
||||
|
||||
// Methods
|
||||
void Reload() const noexcept;
|
||||
void Reset() noexcept;
|
||||
|
||||
void FromJson(const Json::Value& root, FileSource parseSource) const noexcept;
|
||||
Json::Value ToJson(FileSource parseSource) const noexcept;
|
||||
|
||||
// General getters/setters
|
||||
winrt::hstring FilePath() const noexcept;
|
||||
bool IsStatePath(const winrt::hstring& filename);
|
||||
|
||||
// State getters/setters
|
||||
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
|
||||
type name() const noexcept; \
|
||||
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) \
|
||||
type name() const noexcept; \
|
||||
void name(const type& value) noexcept;
|
||||
MTSM_APPLICATION_STATE_FIELDS(MTSM_APPLICATION_STATE_GEN)
|
||||
#undef MTSM_APPLICATION_STATE_GEN
|
||||
|
@ -68,21 +80,24 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
private:
|
||||
struct state_t
|
||||
{
|
||||
#define MTSM_APPLICATION_STATE_GEN(type, name, key, ...) \
|
||||
std::optional<type> name{ __VA_ARGS__ }; \
|
||||
bool name##Changed = false;
|
||||
|
||||
#define MTSM_APPLICATION_STATE_GEN(source, type, name, key, ...) std::optional<type> name{ __VA_ARGS__ };
|
||||
MTSM_APPLICATION_STATE_FIELDS(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() noexcept;
|
||||
void _write() const noexcept;
|
||||
void _read() const noexcept;
|
||||
|
||||
std::filesystem::path _path;
|
||||
til::shared_mutex<state_t> _state;
|
||||
til::throttled_func_trailing<> _throttler;
|
||||
Json::Value _toJsonWithBlob(Json::Value& root, FileSource parseSource) const noexcept;
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -30,12 +30,15 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
void Reload();
|
||||
void Reset();
|
||||
|
||||
String FilePath { get; };
|
||||
Boolean IsStatePath(String filename);
|
||||
|
||||
Windows.Foundation.Collections.IVector<WindowLayout> PersistedWindowLayouts { get; set; };
|
||||
|
||||
Windows.Foundation.Collections.IVector<String> RecentCommands { get; set; };
|
||||
|
||||
Windows.Foundation.Collections.IVector<InfoBarMessage> DismissedMessages { get; set; };
|
||||
|
||||
Windows.Foundation.Collections.IVector<String> AllowedCommandlines { get; set; };
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,8 +287,6 @@ Model::Profile CascadiaSettings::DuplicateProfile(const Model::Profile& source)
|
|||
DUPLICATE_SETTING_MACRO(Commandline);
|
||||
DUPLICATE_SETTING_MACRO(StartingDirectory);
|
||||
DUPLICATE_SETTING_MACRO(AntialiasingMode);
|
||||
DUPLICATE_SETTING_MACRO(ForceFullRepaintRendering);
|
||||
DUPLICATE_SETTING_MACRO(SoftwareRendering);
|
||||
DUPLICATE_SETTING_MACRO(HistorySize);
|
||||
DUPLICATE_SETTING_MACRO(SnapOnInput);
|
||||
DUPLICATE_SETTING_MACRO(AltGrAliasing);
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#include <shlobj.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::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" };
|
||||
|
||||
|
@ -39,86 +43,44 @@ namespace winrt::Microsoft::Terminal::Settings::Model
|
|||
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) };
|
||||
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(),
|
||||
0, // lock shared, 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 };
|
||||
// If the file is owned by the administrators group, trust the
|
||||
// administrators instead of checking the DACL permissions. It's simpler
|
||||
// and more flexible.
|
||||
|
||||
wil::unique_hlocal_security_descriptor sd;
|
||||
PSID psidOwner{ nullptr };
|
||||
// The psidOwner pointer references the security descriptor, so it
|
||||
// doesn't have to be freed separate from sd.
|
||||
const auto status = GetSecurityInfo(handle,
|
||||
SE_FILE_OBJECT,
|
||||
OWNER_SECURITY_INFORMATION,
|
||||
&psidOwner,
|
||||
nullptr,
|
||||
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.
|
||||
// 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:
|
||||
// * 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.
|
||||
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);
|
||||
|
||||
// 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);
|
||||
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.
|
||||
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path)
|
||||
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path, const bool elevatedOnly)
|
||||
{
|
||||
try
|
||||
{
|
||||
return { ReadUTF8File(path) };
|
||||
return { ReadUTF8File(path, elevatedOnly) };
|
||||
}
|
||||
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);
|
||||
|
||||
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.
|
||||
// It's thus important that we first resolve them before generating temporary path.
|
||||
|
|
|
@ -1,41 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
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();
|
||||
|
||||
locked_hfile OpenFileReadSharedLocked(const std::filesystem::path& path);
|
||||
locked_hfile OpenFileRWExclusiveLocked(const std::filesystem::path& path);
|
||||
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);
|
||||
std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly = false);
|
||||
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path, const bool elevatedOnly = false);
|
||||
void WriteUTF8File(const std::filesystem::path& path, const std::string_view& content, const bool elevatedOnly = false);
|
||||
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view& content);
|
||||
}
|
||||
|
|
|
@ -12,11 +12,6 @@ using namespace Microsoft::Terminal::Settings::Model;
|
|||
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
|
||||
|
||||
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 LegacyFontSizeKey{ "fontSize" };
|
||||
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)
|
||||
{
|
||||
auto fontInfo{ winrt::make_self<FontConfig>(std::move(sourceProfile)) };
|
||||
fontInfo->_FontFace = source->_FontFace;
|
||||
fontInfo->_FontSize = source->_FontSize;
|
||||
fontInfo->_FontWeight = source->_FontWeight;
|
||||
fontInfo->_FontAxes = source->_FontAxes;
|
||||
fontInfo->_FontFeatures = source->_FontFeatures;
|
||||
|
||||
#define FONT_SETTINGS_COPY(type, name, jsonKey, ...) \
|
||||
fontInfo->_##name = source->_##name;
|
||||
MTSM_FONT_SETTINGS(FONT_SETTINGS_COPY)
|
||||
#undef FONT_SETTINGS_COPY
|
||||
|
||||
return fontInfo;
|
||||
}
|
||||
|
||||
|
@ -41,11 +37,10 @@ Json::Value FontConfig::ToJson() const
|
|||
{
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
|
||||
JsonUtils::SetValueForKey(json, FontFaceKey, _FontFace);
|
||||
JsonUtils::SetValueForKey(json, FontSizeKey, _FontSize);
|
||||
JsonUtils::SetValueForKey(json, FontWeightKey, _FontWeight);
|
||||
JsonUtils::SetValueForKey(json, FontAxesKey, _FontAxes);
|
||||
JsonUtils::SetValueForKey(json, FontFeaturesKey, _FontFeatures);
|
||||
#define FONT_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
|
||||
JsonUtils::SetValueForKey(json, jsonKey, _##name);
|
||||
MTSM_FONT_SETTINGS(FONT_SETTINGS_TO_JSON)
|
||||
#undef FONT_SETTINGS_TO_JSON
|
||||
|
||||
return json;
|
||||
}
|
||||
|
@ -69,11 +64,10 @@ void FontConfig::LayerJson(const Json::Value& json)
|
|||
{
|
||||
// A font object is defined, use that
|
||||
const auto fontInfoJson = json[JsonKey(FontInfoKey)];
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontFaceKey, _FontFace);
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontSizeKey, _FontSize);
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontWeightKey, _FontWeight);
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontFeaturesKey, _FontFeatures);
|
||||
JsonUtils::GetValueForKey(fontInfoJson, FontAxesKey, _FontAxes);
|
||||
#define FONT_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
|
||||
JsonUtils::GetValueForKey(fontInfoJson, jsonKey, _##name);
|
||||
MTSM_FONT_SETTINGS(FONT_SETTINGS_LAYER_JSON)
|
||||
#undef FONT_SETTINGS_LAYER_JSON
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -19,6 +19,7 @@ Author(s):
|
|||
#include "pch.h"
|
||||
#include "FontConfig.g.h"
|
||||
#include "JsonUtils.h"
|
||||
#include "MTSMSettings.h"
|
||||
#include "../inc/cppwinrt_utils.h"
|
||||
#include "IInheritable.h"
|
||||
#include <DefaultSettings.h>
|
||||
|
@ -39,11 +40,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
Model::Profile SourceProfile();
|
||||
|
||||
INHERITABLE_SETTING(Model::FontConfig, hstring, FontFace, DEFAULT_FONT_FACE);
|
||||
INHERITABLE_SETTING(Model::FontConfig, int32_t, FontSize, DEFAULT_FONT_SIZE);
|
||||
INHERITABLE_SETTING(Model::FontConfig, Windows::UI::Text::FontWeight, FontWeight, DEFAULT_FONT_WEIGHT);
|
||||
INHERITABLE_SETTING(Model::FontConfig, IFontAxesMap, FontAxes);
|
||||
INHERITABLE_SETTING(Model::FontConfig, IFontFeatureMap, FontFeatures);
|
||||
#define FONT_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
|
||||
INHERITABLE_SETTING(Model::FontConfig, type, name, ##__VA_ARGS__)
|
||||
MTSM_FONT_SETTINGS(FONT_SETTINGS_INITIALIZE)
|
||||
#undef FONT_SETTINGS_INITIALIZE
|
||||
|
||||
private:
|
||||
winrt::weak_ref<Profile> _sourceProfile;
|
||||
|
|
|
@ -18,48 +18,7 @@ using namespace winrt::Microsoft::UI::Xaml::Controls;
|
|||
static constexpr std::string_view LegacyKeybindingsKey{ "keybindings" };
|
||||
static constexpr std::string_view ActionsKey{ "actions" };
|
||||
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 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:
|
||||
// - 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
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -132,6 +52,11 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
|||
globals->_actionMap = _actionMap->Copy();
|
||||
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)
|
||||
{
|
||||
for (auto kv : _colorSchemes)
|
||||
|
@ -189,51 +114,15 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::FromJson(const Json::Value&
|
|||
void GlobalAppSettings::LayerJson(const Json::Value& json)
|
||||
{
|
||||
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
|
||||
// "useTabSwitcher" to "tabSwitcherMode". Continue supporting
|
||||
// "useTabSwitcher", but prefer "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 };
|
||||
for (const auto& jsonKey : bindingsKeys)
|
||||
|
@ -293,48 +182,12 @@ Json::Value GlobalAppSettings::ToJson() const
|
|||
{
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
|
||||
// clang-format off
|
||||
JsonUtils::SetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
|
||||
JsonUtils::SetValueForKey(json, AlwaysShowTabsKey, _AlwaysShowTabs);
|
||||
JsonUtils::SetValueForKey(json, ConfirmCloseAllKey, _ConfirmCloseAllTabs);
|
||||
JsonUtils::SetValueForKey(json, InitialRowsKey, _InitialRows);
|
||||
JsonUtils::SetValueForKey(json, InitialColsKey, _InitialCols);
|
||||
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
|
||||
JsonUtils::SetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
|
||||
|
||||
#define GLOBAL_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
|
||||
JsonUtils::SetValueForKey(json, jsonKey, _##name);
|
||||
MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_TO_JSON)
|
||||
#undef GLOBAL_SETTINGS_TO_JSON
|
||||
|
||||
json[JsonKey(ActionsKey)] = _actionMap->ToJson();
|
||||
return json;
|
||||
|
|
|
@ -17,6 +17,7 @@ Author(s):
|
|||
|
||||
#include "GlobalAppSettings.g.h"
|
||||
#include "IInheritable.h"
|
||||
#include "MTSMSettings.h"
|
||||
|
||||
#include "ActionMap.h"
|
||||
#include "Command.h"
|
||||
|
@ -61,46 +62,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
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, 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:
|
||||
#ifdef NDEBUG
|
||||
|
|
|
@ -391,7 +391,6 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
|||
};
|
||||
|
||||
template<typename T>
|
||||
|
||||
struct ConversionTrait<std::unordered_map<std::string, T>>
|
||||
{
|
||||
std::unordered_map<std::string, T> FromJson(const Json::Value& json) const
|
||||
|
|
98
src/cascadia/TerminalSettingsModel/MTSMSettings.h
Normal file
98
src/cascadia/TerminalSettingsModel/MTSMSettings.h
Normal 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)
|
|
@ -50,6 +50,7 @@
|
|||
<DependentUpon>GlobalAppSettings.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IInheritable.h" />
|
||||
<ClInclude Include="MTSMSettings.h" />
|
||||
<ClInclude Include="IDynamicProfileGenerator.h" />
|
||||
<ClInclude Include="JsonUtils.h" />
|
||||
<ClInclude Include="HashUtils.h" />
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
<Filter>json</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IInheritable.h" />
|
||||
<ClInclude Include="MTSMSettings.h" />
|
||||
<ClInclude Include="IconPathConverter.h" />
|
||||
<ClInclude Include="DefaultTerminal.h" />
|
||||
<ClInclude Include="FileUtils.h" />
|
||||
|
|
|
@ -26,24 +26,9 @@ static constexpr std::string_view GuidKey{ "guid" };
|
|||
static constexpr std::string_view SourceKey{ "source" };
|
||||
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 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 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 BellStyleKey{ "bellStyle" };
|
||||
static constexpr std::string_view UnfocusedAppearanceKey{ "unfocusedAppearance" };
|
||||
static constexpr std::string_view BellSoundKey{ "bellSound" };
|
||||
|
||||
|
@ -118,29 +103,18 @@ winrt::com_ptr<Profile> Profile::CopySettings() const
|
|||
profile->_Name = _Name;
|
||||
profile->_Source = _Source;
|
||||
profile->_Hidden = _Hidden;
|
||||
profile->_Icon = _Icon;
|
||||
profile->_CloseOnExit = _CloseOnExit;
|
||||
profile->_TabTitle = _TabTitle;
|
||||
profile->_TabColor = _TabColor;
|
||||
profile->_SuppressApplicationTitle = _SuppressApplicationTitle;
|
||||
profile->_UseAcrylic = _UseAcrylic;
|
||||
profile->_ScrollState = _ScrollState;
|
||||
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->_FontInfo = *fontInfo;
|
||||
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)
|
||||
{
|
||||
Model::AppearanceConfig unfocused{ nullptr };
|
||||
|
@ -198,32 +172,17 @@ void Profile::LayerJson(const Json::Value& json)
|
|||
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
|
||||
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.
|
||||
// Allow it to be permissive.
|
||||
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, 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)))
|
||||
{
|
||||
|
@ -355,29 +314,16 @@ Json::Value Profile::ToJson() const
|
|||
JsonUtils::SetValueForKey(json, HiddenKey, writeBasicSettings ? Hidden() : _Hidden);
|
||||
JsonUtils::SetValueForKey(json, SourceKey, writeBasicSettings ? Source() : _Source);
|
||||
|
||||
// TODO:MSFT:20642297 - Use a sentinel value (-1) for "Infinite scrollback"
|
||||
JsonUtils::SetValueForKey(json, HistorySizeKey, _HistorySize);
|
||||
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
|
||||
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, 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
|
||||
const auto fontInfoImpl = winrt::get_self<FontConfig>(_FontInfo);
|
||||
|
|
|
@ -46,6 +46,7 @@ Author(s):
|
|||
|
||||
#include "Profile.g.h"
|
||||
#include "IInheritable.h"
|
||||
#include "MTSMSettings.h"
|
||||
|
||||
#include "../inc/cppwinrt_utils.h"
|
||||
#include "JsonUtils.h"
|
||||
|
@ -102,45 +103,26 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
void _FinalizeInheritance() override;
|
||||
|
||||
// Special fields
|
||||
WINRT_PROPERTY(bool, Deleted, false);
|
||||
WINRT_PROPERTY(OriginTag, Origin, OriginTag::None);
|
||||
|
||||
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, Source);
|
||||
INHERITABLE_SETTING(Model::Profile, bool, Hidden, false);
|
||||
INHERITABLE_SETTING(Model::Profile, guid, ConnectionType);
|
||||
|
||||
// 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, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING);
|
||||
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, Commandline, L"%SystemRoot%\\System32\\cmd.exe");
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, StartingDirectory);
|
||||
|
||||
INHERITABLE_SETTING(Model::Profile, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale);
|
||||
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);
|
||||
#define PROFILE_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
|
||||
INHERITABLE_SETTING(Model::Profile, type, name, ##__VA_ARGS__)
|
||||
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_INITIALIZE)
|
||||
#undef PROFILE_SETTINGS_INITIALIZE
|
||||
|
||||
private:
|
||||
Model::IAppearanceConfig _DefaultAppearance{ winrt::make<AppearanceConfig>(weak_ref<Model::Profile>(*this)) };
|
||||
|
|
|
@ -74,14 +74,12 @@ namespace Microsoft.Terminal.Settings.Model
|
|||
INHERITABLE_PROFILE_SETTING(IAppearanceConfig, UnfocusedAppearance);
|
||||
|
||||
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(Boolean, SnapOnInput);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AltGrAliasing);
|
||||
INHERITABLE_PROFILE_SETTING(BellStyle, BellStyle);
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, UseAtlasEngine);
|
||||
INHERITABLE_PROFILE_SETTING(Windows.Foundation.Collections.IVector<String>, BellSound);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,6 +275,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
|
||||
// Fill in the remaining properties from the profile
|
||||
_ProfileName = profile.Name();
|
||||
_ProfileSource = profile.Source();
|
||||
_UseAcrylic = profile.UseAcrylic();
|
||||
|
||||
_FontFace = profile.FontInfo().FontFace();
|
||||
|
@ -297,6 +298,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
_SuppressApplicationTitle = profile.SuppressApplicationTitle();
|
||||
}
|
||||
|
||||
_UseAtlasEngine = profile.UseAtlasEngine();
|
||||
_ScrollState = profile.ScrollState();
|
||||
|
||||
_AntialiasingMode = profile.AntialiasingMode();
|
||||
|
|
|
@ -119,6 +119,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||
// ------------------------ End of Core Settings -----------------------
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileSource);
|
||||
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, UseAcrylic, false);
|
||||
INHERITABLE_SETTING(Model::TerminalSettings, double, Opacity, UseAcrylic() ? 0.5 : 1.0);
|
||||
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, 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);
|
||||
|
||||
|
|
|
@ -53,3 +53,6 @@ TRACELOGGING_DECLARE_PROVIDER(g_hSettingsModelProvider);
|
|||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
|
||||
#include <til/mutex.h>
|
||||
#include <til/throttled_func.h>
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace ControlUnitTests
|
|||
// ------------------------ End of Core Settings -----------------------
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, ProfileName);
|
||||
WINRT_PROPERTY(winrt::hstring, ProfileSource);
|
||||
WINRT_PROPERTY(bool, UseAcrylic, false);
|
||||
WINRT_PROPERTY(double, Opacity, .5);
|
||||
WINRT_PROPERTY(winrt::hstring, Padding, DEFAULT_PADDING);
|
||||
|
@ -75,6 +76,7 @@ namespace ControlUnitTests
|
|||
WINRT_PROPERTY(winrt::hstring, EnvironmentVariables);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -2901,15 +2901,9 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs()
|
|||
|
||||
auto defaultAttrs = si.GetAttributes();
|
||||
auto conhostGreenAttrs = TextAttribute();
|
||||
|
||||
// Conhost and Terminal store attributes in different bits.
|
||||
// conhostGreenAttrs.SetIndexedAttributes(std::nullopt,
|
||||
// { static_cast<BYTE>(FOREGROUND_GREEN) });
|
||||
conhostGreenAttrs.SetIndexedBackground(FOREGROUND_GREEN);
|
||||
conhostGreenAttrs.SetIndexedBackground(TextColor::DARK_GREEN);
|
||||
auto terminalGreenAttrs = TextAttribute();
|
||||
// terminalGreenAttrs.SetIndexedAttributes(std::nullopt,
|
||||
// { static_cast<BYTE>(XTERM_GREEN_ATTR) });
|
||||
terminalGreenAttrs.SetIndexedBackground(XTERM_GREEN_ATTR);
|
||||
terminalGreenAttrs.SetIndexedBackground(TextColor::DARK_GREEN);
|
||||
|
||||
// Use an initial ^[[m to start printing with default-on-default
|
||||
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) {
|
||||
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;
|
||||
|
||||
for (short row = 0; row < tb.GetSize().Height(); row++)
|
||||
|
@ -3034,13 +3028,11 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
|
|||
|
||||
auto defaultAttrs = si.GetAttributes();
|
||||
auto conhostBlueAttrs = defaultAttrs;
|
||||
|
||||
// Conhost and Terminal store attributes in different bits.
|
||||
conhostBlueAttrs.SetIndexedForeground(FOREGROUND_GREEN);
|
||||
conhostBlueAttrs.SetIndexedBackground(FOREGROUND_BLUE);
|
||||
conhostBlueAttrs.SetIndexedForeground(TextColor::DARK_GREEN);
|
||||
conhostBlueAttrs.SetIndexedBackground(TextColor::DARK_BLUE);
|
||||
auto terminalBlueAttrs = TextAttribute();
|
||||
terminalBlueAttrs.SetIndexedForeground(XTERM_GREEN_ATTR);
|
||||
terminalBlueAttrs.SetIndexedBackground(XTERM_BLUE_ATTR);
|
||||
terminalBlueAttrs.SetIndexedForeground(TextColor::DARK_GREEN);
|
||||
terminalBlueAttrs.SetIndexedBackground(TextColor::DARK_BLUE);
|
||||
|
||||
// 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
|
||||
|
@ -3083,7 +3075,7 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
|
|||
const auto width = viewport.width<short>();
|
||||
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;
|
||||
|
||||
for (short row = 0; row < viewport.bottom<short>() - 2; row++)
|
||||
|
|
|
@ -84,6 +84,7 @@ AppHost::AppHost() noexcept :
|
|||
_window->WindowMoved({ this, &AppHost::_WindowMoved });
|
||||
_window->HotkeyPressed({ this, &AppHost::_GlobalHotkeyPressed });
|
||||
_window->SetAlwaysOnTop(_logic.GetInitialAlwaysOnTop());
|
||||
_window->ShouldExitFullscreen({ &_logic, &winrt::TerminalApp::AppLogic::RequestExitFullscreen });
|
||||
_window->MakeWindow();
|
||||
|
||||
_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.AlwaysOnTopChanged({ this, &AppHost::_AlwaysOnTopChanged });
|
||||
_logic.RaiseVisualBell({ this, &AppHost::_RaiseVisualBell });
|
||||
_logic.SystemMenuChangeRequested({ this, &AppHost::_SystemMenuChangeRequested });
|
||||
|
||||
_logic.Create();
|
||||
|
||||
|
@ -843,8 +845,30 @@ winrt::Windows::Foundation::IAsyncAction AppHost::_SaveWindowLayouts()
|
|||
|
||||
if (_logic.ShouldUsePersistedLayout())
|
||||
{
|
||||
const auto layoutJsons = _windowManager.GetAllWindowLayouts();
|
||||
_logic.SaveWindowLayoutJsons(layoutJsons);
|
||||
try
|
||||
{
|
||||
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;
|
||||
|
@ -865,6 +889,12 @@ winrt::fire_and_forget AppHost::_SaveWindowLayoutsRepeat()
|
|||
// per 10 seconds, if a save is requested by another source simultaneously.
|
||||
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()();
|
||||
}
|
||||
}
|
||||
|
@ -1248,6 +1278,27 @@ void AppHost::_OpenSystemMenu(const winrt::Windows::Foundation::IInspectable&,
|
|||
_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:
|
||||
// - Creates a Notification Icon and hooks up its handlers
|
||||
// Arguments:
|
||||
|
|
|
@ -96,6 +96,9 @@ private:
|
|||
void _OpenSystemMenu(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
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,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ using namespace ::Microsoft::Console::Types;
|
|||
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
|
||||
#define XAML_HOSTING_WINDOW_CLASS_NAME L"CASCADIA_HOSTING_WINDOW_CLASS"
|
||||
#define IDM_SYSTEM_MENU_BEGIN 0x1000
|
||||
|
||||
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.
|
||||
// We don't really care if this failed or not.
|
||||
TerminalTrySetTransparentBackground(true);
|
||||
|
@ -608,6 +611,20 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
|||
_NotifyNotificationIconMenuItemSelectedHandlers((HMENU)lparam, (UINT)wparam);
|
||||
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:
|
||||
// We'll want to receive this message when explorer.exe restarts
|
||||
// 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, WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
|
||||
void SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept;
|
||||
|
||||
struct SystemMenuItemInfo
|
||||
{
|
||||
winrt::hstring label;
|
||||
winrt::delegate<void()> callback;
|
||||
};
|
||||
|
||||
class IslandWindow :
|
||||
public BaseWindow<IslandWindow>
|
||||
{
|
||||
|
@ -54,6 +60,8 @@ public:
|
|||
void SetMinimizeToNotificationAreaBehavior(bool MinimizeToNotificationArea) 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(WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);
|
||||
|
@ -65,6 +73,7 @@ public:
|
|||
WINRT_CALLBACK(NotifyShowNotificationIconContextMenu, winrt::delegate<void(til::point)>);
|
||||
WINRT_CALLBACK(NotifyNotificationIconMenuItemSelected, winrt::delegate<void(HMENU, UINT)>);
|
||||
WINRT_CALLBACK(NotifyReAddNotificationIcon, winrt::delegate<void()>);
|
||||
WINRT_CALLBACK(ShouldExitFullscreen, winrt::delegate<void()>);
|
||||
|
||||
WINRT_CALLBACK(WindowMoved, winrt::delegate<void()>);
|
||||
|
||||
|
@ -131,6 +140,9 @@ protected:
|
|||
|
||||
bool _minimizeToNotificationArea{ false };
|
||||
|
||||
std::unordered_map<UINT, SystemMenuItemInfo> _systemMenuItems;
|
||||
UINT _systemMenuNextItemId;
|
||||
|
||||
private:
|
||||
// This minimum width allows for width the tabs fit
|
||||
static constexpr long minimumWidth = 460L;
|
||||
|
|
|
@ -843,7 +843,11 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept
|
|||
HPAINTBUFFER buf = BeginBufferedPaint(hdc.get(), &rcRest, BPBF_TOPDOWNDIB, ¶ms, &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());
|
||||
|
|
|
@ -79,4 +79,14 @@
|
|||
<!-- This feature will not ship to Stable until it is complete. -->
|
||||
<alwaysDisabledReleaseTokens />
|
||||
</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>
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -231,7 +231,7 @@ InputBuffer* const CONSOLE_INFORMATION::GetActiveInputBuffer() const
|
|||
COLORREF CONSOLE_INFORMATION::GetDefaultForeground() const noexcept
|
||||
{
|
||||
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:
|
||||
|
@ -246,23 +246,37 @@ COLORREF CONSOLE_INFORMATION::GetDefaultForeground() const noexcept
|
|||
COLORREF CONSOLE_INFORMATION::GetDefaultBackground() const noexcept
|
||||
{
|
||||
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:
|
||||
// - Get the colors of a particular text attribute, using our color table,
|
||||
// and our configured default attributes.
|
||||
// Arguments:
|
||||
// - attr: the TextAttribute to retrieve the foreground color of.
|
||||
// - attr: the TextAttribute to retrieve the foreground and background color of.
|
||||
// Return Value:
|
||||
// - The color values of the attribute's foreground and background.
|
||||
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);
|
||||
return attr.CalculateRgbColors(
|
||||
GetColorTable(),
|
||||
GetDefaultForeground(),
|
||||
GetDefaultBackground(),
|
||||
defaultFg,
|
||||
defaultBg,
|
||||
IsScreenReversed(),
|
||||
_blinkingState.IsBlinkingFaint());
|
||||
}
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
<ProjectReference Include="..\..\renderer\base\lib\base.vcxproj">
|
||||
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj">
|
||||
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
|
||||
</ProjectReference>
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
<ProjectReference Include="..\..\renderer\base\lib\base.vcxproj">
|
||||
<Project>{af0a096a-8b3a-4949-81ef-7df8f0fee91f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj">
|
||||
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
|
||||
</ProjectReference>
|
||||
|
@ -71,6 +74,7 @@
|
|||
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
// GetConsoleAlias
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
|
||||
class AliasTests
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::Common;
|
||||
|
||||
// This class is intended to test boundary conditions for:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "precomp.h"
|
||||
|
||||
using namespace WEX::TestExecution;
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::Common;
|
||||
|
||||
// This class is intended to test:
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <future>
|
||||
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using WEX::TestExecution::TestData;
|
||||
using namespace WEX::Common;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
|
||||
static const COORD c_coordZero = { 0, 0 };
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#define NUMBER_OF_SCENARIO_INPUTS 10
|
||||
#define READ_BATCH 3
|
||||
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::Common;
|
||||
|
||||
// This class is intended to test:
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
using namespace Microsoft::Console::Types;
|
||||
using namespace WEX::TestExecution;
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::Common;
|
||||
|
||||
class OutputTests
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#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
|
||||
class PolicyTests
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "precomp.h"
|
||||
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::Common;
|
||||
|
||||
// This class is intended to test:
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#define ENGLISH_US_CP 437u
|
||||
#define JAPANESE_CP 932u
|
||||
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using WEX::TestExecution::TestData;
|
||||
using namespace WEX::Common;
|
||||
|
||||
|
@ -2320,9 +2320,6 @@ void ReadStringWithReadConsoleInputAHelper(HANDLE hIn, PCSTR pszExpectedText, si
|
|||
|
||||
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;
|
||||
if (!VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleInputA(hIn, irRead, (DWORD)cbBuffer, &dwRead), L"Attempt to read input into buffer."))
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "precomp.h"
|
||||
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::Common;
|
||||
|
||||
// This class is intended to provide a canary (simple launch test)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "precomp.h"
|
||||
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::Common;
|
||||
|
||||
HANDLE Common::_hConsole = INVALID_HANDLE_VALUE;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
using WEX::Logging::Log;
|
||||
using namespace WEX::Logging;
|
||||
|
||||
class KeyPressTests
|
||||
{
|
||||
|
|
|
@ -605,7 +605,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
|
|||
|
||||
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 });
|
||||
|
@ -1978,7 +1978,7 @@ void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo)
|
|||
Globals& g = ServiceLocator::LocateGlobals();
|
||||
CONSOLE_INFORMATION& gci = g.getConsoleInformation();
|
||||
|
||||
value = gci.GetColorTableEntry(::Xterm256ToWindowsIndex(index));
|
||||
value = gci.GetColorTableEntry(index);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -2004,7 +2004,7 @@ void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo)
|
|||
Globals& g = ServiceLocator::LocateGlobals();
|
||||
CONSOLE_INFORMATION& gci = g.getConsoleInformation();
|
||||
|
||||
gci.SetColorTableEntry(::Xterm256ToWindowsIndex(index), value);
|
||||
gci.SetColorTableEntry(index, value);
|
||||
|
||||
// Update the screen colors if we're not a pty
|
||||
// No need to force a redraw in pty mode.
|
||||
|
|
|
@ -22,10 +22,7 @@ Revision History:
|
|||
#include "ConsoleArguments.hpp"
|
||||
#include "ApiRoutines.h"
|
||||
|
||||
#include "../renderer/inc/IRenderData.hpp"
|
||||
#include "../renderer/inc/IRenderEngine.hpp"
|
||||
#include "../renderer/inc/IRenderer.hpp"
|
||||
#include "../renderer/inc/IFontDefaultList.hpp"
|
||||
#include "../renderer/base/Renderer.hpp"
|
||||
|
||||
#include "../server/DeviceComm.h"
|
||||
#include "../server/ConDrvDeviceComm.h"
|
||||
|
@ -62,7 +59,7 @@ public:
|
|||
|
||||
std::vector<wchar_t> WordDelimiters;
|
||||
|
||||
Microsoft::Console::Render::IRenderer* pRender;
|
||||
Microsoft::Console::Render::Renderer* pRender;
|
||||
|
||||
Microsoft::Console::Render::IFontDefaultList* pFontDefaultList;
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
<ClCompile Include="..\CommandListPopup.cpp" />
|
||||
<ClCompile Include="..\CopyFromCharPopup.cpp" />
|
||||
<ClCompile Include="..\CopyToCharPopup.cpp" />
|
||||
<ClCompile Include="..\conattrs.cpp" />
|
||||
<ClCompile Include="..\ConsoleArguments.cpp" />
|
||||
<ClCompile Include="..\CursorBlinker.cpp" />
|
||||
<ClCompile Include="..\readDataCooked.cpp" />
|
||||
|
|
|
@ -138,9 +138,6 @@
|
|||
<ClCompile Include="..\writeData.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\conattrs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\VtInputThread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -34,13 +34,13 @@ using Microsoft::Console::Interactivity::ServiceLocator;
|
|||
// - OriginalCursorPosition -
|
||||
// - NumberOfVisibleChars
|
||||
// - CtrlWakeupMask - Special client parameter to interrupt editing, end the wait, and return control to the client application
|
||||
// - CommandHistory -
|
||||
// - Echo -
|
||||
// - InsertMode -
|
||||
// - Processed -
|
||||
// - Line -
|
||||
// - 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
|
||||
// - pClientProcess - Attached process handle object
|
||||
// Return Value:
|
||||
// - THROW: Throws E_INVALIDARG for invalid pointers.
|
||||
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_ PWCHAR UserBuffer,
|
||||
_In_ ULONG CtrlWakeupMask,
|
||||
_In_ CommandHistory* CommandHistory,
|
||||
const std::wstring_view exeName,
|
||||
const std::string_view initialData) :
|
||||
_In_ const std::wstring_view exeName,
|
||||
_In_ const std::string_view initialData,
|
||||
_In_ ConsoleProcessHandle* const pClientProcess) :
|
||||
ReadData(pInputBuffer, pInputReadHandleData),
|
||||
_screenInfo{ screenInfo },
|
||||
_bytesRead{ 0 },
|
||||
|
@ -62,7 +62,7 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
|
|||
_exeName{ exeName },
|
||||
_pdwNumBytes{ nullptr },
|
||||
|
||||
_commandHistory{ CommandHistory },
|
||||
_commandHistory{ CommandHistory::s_Find((HANDLE)pClientProcess) },
|
||||
_controlKeyState{ 0 },
|
||||
_ctrlWakeupMask{ CtrlWakeupMask },
|
||||
_visibleCharCount{ 0 },
|
||||
|
@ -73,7 +73,8 @@ COOKED_READ_DATA::COOKED_READ_DATA(_In_ InputBuffer* const pInputBuffer,
|
|||
_lineInput{ WI_IsFlagSet(pInputBuffer->InputMode, ENABLE_LINE_INPUT) },
|
||||
_processedInput{ WI_IsFlagSet(pInputBuffer->InputMode, ENABLE_PROCESSED_INPUT) },
|
||||
_insertMode{ ServiceLocator::LocateGlobals().getConsoleInformation().GetInsertMode() },
|
||||
_unicode{ false }
|
||||
_unicode{ false },
|
||||
_clientProcess{ pClientProcess }
|
||||
{
|
||||
#ifndef UNIT_TESTING
|
||||
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).
|
||||
PWCHAR StringPtr = _backupLimit;
|
||||
size_t StringLength = _bytesRead;
|
||||
size_t StringLength = _bytesRead / sizeof(WCHAR);
|
||||
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)
|
||||
{
|
||||
StringLength = i * sizeof(WCHAR);
|
||||
StringLength = i;
|
||||
FoundCR = true;
|
||||
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.
|
||||
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)));
|
||||
}
|
||||
|
||||
Tracing::s_TraceCookedRead(_backupLimit);
|
||||
Tracing::s_TraceCookedRead(_clientProcess,
|
||||
_backupLimit,
|
||||
base::saturated_cast<ULONG>(StringLength));
|
||||
|
||||
// check for alias
|
||||
ProcessAliases(LineCount);
|
||||
|
|
|
@ -39,9 +39,9 @@ public:
|
|||
_In_ size_t UserBufferSize,
|
||||
_In_ PWCHAR UserBuffer,
|
||||
_In_ ULONG CtrlWakeupMask,
|
||||
_In_ CommandHistory* CommandHistory,
|
||||
const std::wstring_view exeName,
|
||||
const std::string_view initialData);
|
||||
_In_ const std::wstring_view exeName,
|
||||
_In_ const std::string_view initialData,
|
||||
_In_ ConsoleProcessHandle* const pClientProcess);
|
||||
|
||||
~COOKED_READ_DATA() override;
|
||||
COOKED_READ_DATA(COOKED_READ_DATA&&) = default;
|
||||
|
@ -156,6 +156,8 @@ private:
|
|||
bool _insertMode;
|
||||
bool _unicode;
|
||||
|
||||
ConsoleProcessHandle* const _clientProcess;
|
||||
|
||||
[[nodiscard]] NTSTATUS _readCharInputLoop(const bool isUnicode, size_t& numBytes) noexcept;
|
||||
|
||||
[[nodiscard]] NTSTATUS _handlePostCharInputLoop(const bool isUnicode, size_t& numBytes, ULONG& controlKeyState) noexcept;
|
||||
|
|
|
@ -310,7 +310,7 @@ void Registry::LoadFromRegistry(_In_ PCWSTR const pwszConsoleTitle)
|
|||
nullptr);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
_pSettings->SetColorTableEntry(i, dwValue);
|
||||
_pSettings->SetLegacyColorTableEntry(i, dwValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -110,6 +110,8 @@ void RenderData::UnlockConsole() noexcept
|
|||
const TextAttribute RenderData::GetDefaultBrushColors() noexcept
|
||||
{
|
||||
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
_defaultForeground = gci.GetDefaultForeground();
|
||||
_defaultBackground = gci.GetDefaultBackground();
|
||||
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
|
||||
{
|
||||
const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
return gci.LookupAttributeColors(attr);
|
||||
return gci.LookupAttributeColors(attr, _defaultForeground, _defaultBackground);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue