Compare commits
216 commits
main
...
dev/duhowe
Author | SHA1 | Date | |
---|---|---|---|
52d1e788f7 | |||
214af0bb74 | |||
b90cf8148d | |||
6939ff77cf | |||
174e413f8e | |||
e24f4d5638 | |||
fd2f584019 | |||
15ab87f5d4 | |||
aa9577bfc7 | |||
37c4cbee74 | |||
77975e88f0 | |||
065e5f7d90 | |||
d675fd824a | |||
b421ee6ca0 | |||
841ced7e57 | |||
056446cd3e | |||
25947c2f40 | |||
2445cedb92 | |||
8e43c9d8ce | |||
fd72b7992e | |||
bad27a97ba | |||
a1bfa332f3 | |||
8313987490 | |||
97d11d1bd3 | |||
7f03d4d1ea | |||
33e96e7e66 | |||
efdc0909e8 | |||
999f21fcf8 | |||
7bb8975953 | |||
8532dd692e | |||
a338ca168c | |||
5adb327703 | |||
1a7649ce21 | |||
a9e706c573 | |||
2a18d7dae3 | |||
ae833a77bd | |||
88f2e64bb3 | |||
6e8a2adbd9 | |||
59c193c22a | |||
713f72e1e5 | |||
5cd8096d42 | |||
147101f833 | |||
5173ea30f5 | |||
9eeea4a9d0 | |||
d51c2cff35 | |||
08cbd16d47 | |||
db9cbf3fa8 | |||
7024f44c96 | |||
1c66877b72 | |||
5253c114ae | |||
fdc574929b | |||
c09bdbd25e | |||
ce6a9c571b | |||
a93d17ef09 | |||
4f16dfb5fd | |||
b21287140d | |||
25b2675d8d | |||
fd849a5241 | |||
4976a091a0 | |||
5acbad512e | |||
eebd1a078a | |||
6e2150ba5b | |||
1167e20b0f | |||
01aa26c522 | |||
21ba58ca29 | |||
0fa10cd3ef | |||
953620669d | |||
a00e9edecc | |||
94d6bfbf2d | |||
1915a06f6e | |||
0ef867319d | |||
deb494f6ef | |||
d32fac4d3f | |||
939177bdab | |||
be38330ddf | |||
487edb9071 | |||
6c9b399048 | |||
5fdef429a8 | |||
83e7aead57 | |||
6da5d79d47 | |||
c90eb8763a | |||
25c34dfcad | |||
9b4ae9ec55 | |||
3a8a83a810 | |||
51486a4168 | |||
bdf08165d4 | |||
b9979ffaf8 | |||
7fb490629b | |||
d6d708796a | |||
242de14722 | |||
69f1068050 | |||
90b79624ca | |||
fe5a78cff1 | |||
21d6ffe89c | |||
945c81d1df | |||
f111c6d72d | |||
f087dd8236 | |||
bf9bf0e138 | |||
7c288517a5 | |||
8c7ce77811 | |||
01cef2f3dc | |||
4a700cd1cc | |||
217742c1ff | |||
48ca704816 | |||
634b6854dc | |||
28cbad1470 | |||
94f4ef5601 | |||
6babb4e73a | |||
282c03c374 | |||
916096643e | |||
e3a50cfdee | |||
1aa2849d94 | |||
17829f438b | |||
888e1572d2 | |||
4912b65967 | |||
03711944f1 | |||
70b9f8ce5f | |||
a9de82e4ee | |||
4f7e883673 | |||
31e799859f | |||
1413d0145a | |||
fbba74e89b | |||
faa06f807d | |||
bf3c6e7029 | |||
f49c3fca01 | |||
ae99ce9c36 | |||
0e7217d354 | |||
aea37520b3 | |||
3c1866ac53 | |||
48b20de4f4 | |||
9ff2775122 | |||
4a1baf0006 | |||
b4e0496eff | |||
ff333870fc | |||
866832b665 | |||
56992296bf | |||
d053f6cc9e | |||
c26dd6b1db | |||
c7536edfa8 | |||
a751156fcc | |||
620ee302fd | |||
abb847b4c7 | |||
7fc2f10bbd | |||
4b18bb415e | |||
d6989ec9d1 | |||
981d8cc9c8 | |||
dad065e0fe | |||
43ec102343 | |||
a3ac32ab25 | |||
5e9d0b8195 | |||
62fe8235dc | |||
5ff9a247d4 | |||
7e2b371dae | |||
02e9871f2a | |||
eee657b502 | |||
a6e044d91c | |||
f3738f5c1b | |||
7e2e4eaf49 | |||
8635537ebc | |||
de9dc32aa0 | |||
64d02f2b2b | |||
94c4cca176 | |||
b2796019f8 | |||
b755eb0f20 | |||
b1b1befeb9 | |||
507a48ed68 | |||
5a8e27e60a | |||
9b3b9e0109 | |||
7f9f75cab3 | |||
d0f05f60e9 | |||
56850639c5 | |||
a4acdeb5f2 | |||
56d5f9ee3a | |||
d944a68ded | |||
723037ef99 | |||
54a002762a | |||
47d55a8fd0 | |||
edd71265d8 | |||
6757452d6d | |||
4e69a32de7 | |||
da0cc7bae5 | |||
51e0473560 | |||
c106f64bc7 | |||
6be697221d | |||
d6c2fb593d | |||
1e3a319314 | |||
4da965f901 | |||
4f697eca92 | |||
1111d41347 | |||
6265f4f1d7 | |||
7854abe0a3 | |||
9a1cf5ac6e | |||
aef422d5f1 | |||
8569211d0f | |||
721b6367a2 | |||
5197dc4e50 | |||
880222dc1b | |||
447c2f9d4f | |||
b592155d2b | |||
04145d4fe0 | |||
64898b1caf | |||
e5dc64e085 | |||
58c6646132 | |||
9b32681ae1 | |||
7f29e1e268 | |||
736a351c27 | |||
631cdf7b18 | |||
7fb7d64b91 | |||
1ee3522cd8 | |||
ed1cf2aeac | |||
c66a56656e | |||
14d21f492b | |||
ccbcb425da | |||
2857324777 | |||
eb243f5e11 | |||
42c3eea136 |
7
.github/actions/spelling/allow/apis.txt
vendored
7
.github/actions/spelling/allow/apis.txt
vendored
|
@ -43,12 +43,14 @@ fullkbd
|
||||||
futex
|
futex
|
||||||
GETDESKWALLPAPER
|
GETDESKWALLPAPER
|
||||||
GETHIGHCONTRAST
|
GETHIGHCONTRAST
|
||||||
|
GETMOUSEHOVERTIME
|
||||||
Hashtable
|
Hashtable
|
||||||
HIGHCONTRASTON
|
HIGHCONTRASTON
|
||||||
HIGHCONTRASTW
|
HIGHCONTRASTW
|
||||||
hotkeys
|
hotkeys
|
||||||
href
|
href
|
||||||
hrgn
|
hrgn
|
||||||
|
HTCLOSE
|
||||||
IActivation
|
IActivation
|
||||||
IApp
|
IApp
|
||||||
IAppearance
|
IAppearance
|
||||||
|
@ -93,11 +95,14 @@ MENUINFO
|
||||||
MENUITEMINFOW
|
MENUITEMINFOW
|
||||||
memicmp
|
memicmp
|
||||||
mptt
|
mptt
|
||||||
|
MOUSELEAVE
|
||||||
mov
|
mov
|
||||||
msappx
|
msappx
|
||||||
MULTIPLEUSE
|
MULTIPLEUSE
|
||||||
NCHITTEST
|
NCHITTEST
|
||||||
NCLBUTTONDBLCLK
|
NCLBUTTONDBLCLK
|
||||||
|
NCMOUSELEAVE
|
||||||
|
NCMOUSEMOVE
|
||||||
NCRBUTTONDBLCLK
|
NCRBUTTONDBLCLK
|
||||||
NIF
|
NIF
|
||||||
NIN
|
NIN
|
||||||
|
@ -163,9 +168,11 @@ TASKBARCREATED
|
||||||
TBPF
|
TBPF
|
||||||
THEMECHANGED
|
THEMECHANGED
|
||||||
tlg
|
tlg
|
||||||
|
TME
|
||||||
tmp
|
tmp
|
||||||
tolower
|
tolower
|
||||||
toupper
|
toupper
|
||||||
|
TRACKMOUSEEVENT
|
||||||
TTask
|
TTask
|
||||||
TVal
|
TVal
|
||||||
UChar
|
UChar
|
||||||
|
|
|
@ -55,8 +55,12 @@ namespace SettingsModelLocalTests
|
||||||
TerminalSettings settings;
|
TerminalSettings settings;
|
||||||
VERIFY_IS_NOT_NULL(settings);
|
VERIFY_IS_NOT_NULL(settings);
|
||||||
auto oldFontSize = settings.FontSize();
|
auto oldFontSize = settings.FontSize();
|
||||||
settings.FontSize(oldFontSize + 5);
|
|
||||||
auto newFontSize = settings.FontSize();
|
auto selfSettings = winrt::make_self<implementation::TerminalSettings>();
|
||||||
|
VERIFY_ARE_EQUAL(oldFontSize, selfSettings->FontSize());
|
||||||
|
|
||||||
|
selfSettings->FontSize(oldFontSize + 5);
|
||||||
|
auto newFontSize = selfSettings->FontSize();
|
||||||
VERIFY_ARE_NOT_EQUAL(oldFontSize, newFontSize);
|
VERIFY_ARE_NOT_EQUAL(oldFontSize, newFontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,6 @@ namespace TerminalAppLocalTests
|
||||||
TEST_METHOD(TestWindowRenameSuccessful);
|
TEST_METHOD(TestWindowRenameSuccessful);
|
||||||
TEST_METHOD(TestWindowRenameFailure);
|
TEST_METHOD(TestWindowRenameFailure);
|
||||||
|
|
||||||
TEST_METHOD(TestControlSettingsHasParent);
|
|
||||||
TEST_METHOD(TestPreviewCommitScheme);
|
TEST_METHOD(TestPreviewCommitScheme);
|
||||||
TEST_METHOD(TestPreviewDismissScheme);
|
TEST_METHOD(TestPreviewDismissScheme);
|
||||||
TEST_METHOD(TestPreviewSchemeWhilePreviewing);
|
TEST_METHOD(TestPreviewSchemeWhilePreviewing);
|
||||||
|
@ -134,10 +133,6 @@ namespace TerminalAppLocalTests
|
||||||
// Just creating it is enough to know that everything is working.
|
// Just creating it is enough to know that everything is working.
|
||||||
TerminalSettings settings;
|
TerminalSettings settings;
|
||||||
VERIFY_IS_NOT_NULL(settings);
|
VERIFY_IS_NOT_NULL(settings);
|
||||||
auto oldFontSize = settings.FontSize();
|
|
||||||
settings.FontSize(oldFontSize + 5);
|
|
||||||
auto newFontSize = settings.FontSize();
|
|
||||||
VERIFY_ARE_NOT_EQUAL(oldFontSize, newFontSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabTests::TryCreateConnectionType()
|
void TabTests::TryCreateConnectionType()
|
||||||
|
@ -1297,25 +1292,6 @@ namespace TerminalAppLocalTests
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabTests::TestControlSettingsHasParent()
|
|
||||||
{
|
|
||||||
Log::Comment(L"Ensure that when we create a control, it always has a parent TerminalSettings");
|
|
||||||
|
|
||||||
auto page = _commonSetup();
|
|
||||||
VERIFY_IS_NOT_NULL(page);
|
|
||||||
|
|
||||||
TestOnUIThread([&page]() {
|
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
|
||||||
|
|
||||||
const auto& originalSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void TabTests::TestPreviewCommitScheme()
|
void TabTests::TestPreviewCommitScheme()
|
||||||
{
|
{
|
||||||
Log::Comment(L"Preview a color scheme. Make sure it's applied, then committed accordingly");
|
Log::Comment(L"Preview a color scheme. Make sure it's applied, then committed accordingly");
|
||||||
|
@ -1327,12 +1303,9 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& originalSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1346,17 +1319,12 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& previewSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(previewSettings);
|
|
||||||
|
|
||||||
const auto& originalSettings = previewSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
Log::Comment(L"Color should be changed to the preview");
|
Log::Comment(L"Color should be changed to the preview");
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||||
|
|
||||||
// And we should have stored a function to revert the change.
|
// And we should have stored a function to revert the change.
|
||||||
VERIFY_ARE_EQUAL(1u, page->_restorePreviewFuncs.size());
|
VERIFY_ARE_EQUAL(1u, page->_restorePreviewFuncs.size());
|
||||||
});
|
});
|
||||||
|
@ -1373,20 +1341,22 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& originalSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
const auto& grandparentSettings = originalSettings.GetParent();
|
|
||||||
VERIFY_IS_NULL(grandparentSettings);
|
|
||||||
|
|
||||||
Log::Comment(L"Color should be changed");
|
Log::Comment(L"Color should be changed");
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||||
|
|
||||||
// After preview there should be no more restore functions to execute.
|
// After preview there should be no more restore functions to execute.
|
||||||
VERIFY_ARE_EQUAL(0u, page->_restorePreviewFuncs.size());
|
VERIFY_ARE_EQUAL(0u, page->_restorePreviewFuncs.size());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Log::Comment(L"Sleep to let events propagate");
|
||||||
|
// If you don't do this, we will _sometimes_ crash as we're tearing down
|
||||||
|
// the control from this test as we start the next one. We crash
|
||||||
|
// somewhere in the CursorPositionChanged handler. It's annoying, but
|
||||||
|
// this works.
|
||||||
|
Sleep(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabTests::TestPreviewDismissScheme()
|
void TabTests::TestPreviewDismissScheme()
|
||||||
|
@ -1400,12 +1370,9 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& originalSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1419,15 +1386,9 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& previewSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(previewSettings);
|
|
||||||
|
|
||||||
const auto& originalSettings = previewSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
Log::Comment(L"Color should be changed to the preview");
|
Log::Comment(L"Color should be changed to the preview");
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||||
});
|
});
|
||||||
|
@ -1441,18 +1402,14 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& originalSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
const auto& grandparentSettings = originalSettings.GetParent();
|
|
||||||
VERIFY_IS_NULL(grandparentSettings);
|
|
||||||
|
|
||||||
Log::Comment(L"Color should be the same as it originally was");
|
Log::Comment(L"Color should be the same as it originally was");
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||||
});
|
});
|
||||||
|
Log::Comment(L"Sleep to let events propagate");
|
||||||
|
Sleep(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabTests::TestPreviewSchemeWhilePreviewing()
|
void TabTests::TestPreviewSchemeWhilePreviewing()
|
||||||
|
@ -1468,12 +1425,9 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& originalSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1487,15 +1441,9 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& previewSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(previewSettings);
|
|
||||||
|
|
||||||
const auto& originalSettings = previewSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
Log::Comment(L"Color should be changed to the preview");
|
Log::Comment(L"Color should be changed to the preview");
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||||
});
|
});
|
||||||
|
@ -1510,15 +1458,9 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& previewSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(previewSettings);
|
|
||||||
|
|
||||||
const auto& originalSettings = previewSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
Log::Comment(L"Color should be changed to the preview");
|
Log::Comment(L"Color should be changed to the preview");
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
|
||||||
});
|
});
|
||||||
|
@ -1535,18 +1477,14 @@ namespace TerminalAppLocalTests
|
||||||
const auto& activeControl{ page->_GetActiveControl() };
|
const auto& activeControl{ page->_GetActiveControl() };
|
||||||
VERIFY_IS_NOT_NULL(activeControl);
|
VERIFY_IS_NOT_NULL(activeControl);
|
||||||
|
|
||||||
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
|
const auto& controlSettings = activeControl.Settings();
|
||||||
VERIFY_IS_NOT_NULL(controlSettings);
|
VERIFY_IS_NOT_NULL(controlSettings);
|
||||||
|
|
||||||
const auto& originalSettings = controlSettings.GetParent();
|
|
||||||
VERIFY_IS_NOT_NULL(originalSettings);
|
|
||||||
|
|
||||||
const auto& grandparentSettings = originalSettings.GetParent();
|
|
||||||
VERIFY_IS_NULL(grandparentSettings);
|
|
||||||
|
|
||||||
Log::Comment(L"Color should be changed");
|
Log::Comment(L"Color should be changed");
|
||||||
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
|
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
|
||||||
});
|
});
|
||||||
|
Log::Comment(L"Sleep to let events propagate");
|
||||||
|
Sleep(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabTests::TestClampSwitchToTab()
|
void TabTests::TestClampSwitchToTab()
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
<ClCompile Include="CommandlineTest.cpp" />
|
<ClCompile Include="CommandlineTest.cpp" />
|
||||||
<ClCompile Include="SettingsTests.cpp" />
|
<ClCompile Include="SettingsTests.cpp" />
|
||||||
<ClCompile Include="TabTests.cpp" />
|
<ClCompile Include="TabTests.cpp" />
|
||||||
|
<ClCompile Include="TrustCommandlineTests.cpp" />
|
||||||
<ClCompile Include="FilteredCommandTests.cpp" />
|
<ClCompile Include="FilteredCommandTests.cpp" />
|
||||||
<ClCompile Include="pch.cpp">
|
<ClCompile Include="pch.cpp">
|
||||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||||
|
|
123
src/cascadia/LocalTests_TerminalApp/TrustCommandlineTests.cpp
Normal file
123
src/cascadia/LocalTests_TerminalApp/TrustCommandlineTests.cpp
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
//
|
||||||
|
// A series of tests for the TerminalPage::_isTrustedCommandline function.
|
||||||
|
// That's a heuristic function for deciding if we should automatically trust
|
||||||
|
// certain commandlines by default. The logic in there is weird and there are
|
||||||
|
// lots of edge cases, so it's easier to just write a unit test.
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "../TerminalApp/TerminalPage.h"
|
||||||
|
|
||||||
|
using namespace Microsoft::Console;
|
||||||
|
using namespace TerminalApp;
|
||||||
|
using namespace winrt::TerminalApp;
|
||||||
|
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||||
|
|
||||||
|
using namespace WEX::Logging;
|
||||||
|
using namespace WEX::TestExecution;
|
||||||
|
using namespace WEX::Common;
|
||||||
|
|
||||||
|
using namespace winrt::Windows::ApplicationModel::DataTransfer;
|
||||||
|
using namespace winrt::Windows::Foundation::Collections;
|
||||||
|
using namespace winrt::Windows::System;
|
||||||
|
using namespace winrt::Windows::UI::Xaml;
|
||||||
|
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||||
|
using namespace winrt::Windows::UI::Core;
|
||||||
|
using namespace winrt::Windows::UI::Text;
|
||||||
|
|
||||||
|
namespace winrt
|
||||||
|
{
|
||||||
|
namespace MUX = Microsoft::UI::Xaml;
|
||||||
|
namespace WUX = Windows::UI::Xaml;
|
||||||
|
using IInspectable = Windows::Foundation::IInspectable;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace TerminalAppLocalTests
|
||||||
|
{
|
||||||
|
class TrustCommandlineTests
|
||||||
|
{
|
||||||
|
BEGIN_TEST_CLASS(TrustCommandlineTests)
|
||||||
|
END_TEST_CLASS()
|
||||||
|
|
||||||
|
TEST_METHOD(SimpleTests);
|
||||||
|
TEST_METHOD(TestCommandlineWithArgs);
|
||||||
|
TEST_METHOD(TestCommandlineWithSpaces);
|
||||||
|
TEST_METHOD(TestCommandlineWithEnvVars);
|
||||||
|
TEST_METHOD(WslTests);
|
||||||
|
TEST_METHOD(TestPwshLocation);
|
||||||
|
|
||||||
|
bool trust(std::wstring_view cmdline);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool TrustCommandlineTests::trust(std::wstring_view cmdline)
|
||||||
|
{
|
||||||
|
return implementation::TerminalPage::_isTrustedCommandline(cmdline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrustCommandlineTests::SimpleTests()
|
||||||
|
{
|
||||||
|
VERIFY_IS_TRUE(trust(L"C:\\Windows\\System32\\cmd.exe"));
|
||||||
|
VERIFY_IS_TRUE(trust(L"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"));
|
||||||
|
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\i-definitely-don't-exist.exe"));
|
||||||
|
|
||||||
|
Log::Comment(L"These are not fully qualified, and _shouldn't_ be trusted");
|
||||||
|
VERIFY_IS_FALSE(trust(L"cmd.exe"));
|
||||||
|
VERIFY_IS_FALSE(trust(L"powershell.exe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrustCommandlineTests::TestCommandlineWithArgs()
|
||||||
|
{
|
||||||
|
Log::Comment(L"These are sneaky things that _shouldn't_ be trusted");
|
||||||
|
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\cmd.exe /k echo Boo!"));
|
||||||
|
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\cmd.exe /k echo Boo! & cmd.exe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrustCommandlineTests::TestCommandlineWithSpaces()
|
||||||
|
{
|
||||||
|
Log::Comment(L"This is a valid place for powershell to live, and the space can be tricky");
|
||||||
|
VERIFY_IS_TRUE(trust(L"C:\\Program Files\\PowerShell\\7\\pwsh.exe"));
|
||||||
|
|
||||||
|
Log::Comment(L"These are sneaky things that _shouldn't_ be trusted");
|
||||||
|
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System 32\\cmd.exe"));
|
||||||
|
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\ cmd.exe"));
|
||||||
|
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\cmd.exe /c cmd.exe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrustCommandlineTests::TestCommandlineWithEnvVars()
|
||||||
|
{
|
||||||
|
Log::Comment(L"Make sure we auto-expand environment variables");
|
||||||
|
|
||||||
|
VERIFY_IS_TRUE(trust(L"%WINDIR%\\system32\\cmd.exe"));
|
||||||
|
VERIFY_IS_TRUE(trust(L"%WINDIR%\\system32\\WindowsPowerShell\\v1.0\\powershell.exe"));
|
||||||
|
VERIFY_IS_TRUE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrustCommandlineTests::WslTests()
|
||||||
|
{
|
||||||
|
Log::Comment(L"We are explicitly deciding to not auto-approve "
|
||||||
|
L"`wsl.exe -d distro`-like commandlines. If we change this"
|
||||||
|
L" policy, remove this test.");
|
||||||
|
|
||||||
|
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\wsl"));
|
||||||
|
VERIFY_IS_TRUE(trust(L"C:\\Windows\\System32\\wsl.exe"), L"This we will trust though, since it's an exe in system32");
|
||||||
|
VERIFY_IS_FALSE(trust(L"C:\\Windows\\System32\\wsl.exe -d Ubuntu"));
|
||||||
|
VERIFY_IS_FALSE(trust(L"wsl.exe"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrustCommandlineTests::TestPwshLocation()
|
||||||
|
{
|
||||||
|
Log::Comment(L"Test various locations that pwsh.exe can be in");
|
||||||
|
|
||||||
|
VERIFY_IS_TRUE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe"));
|
||||||
|
VERIFY_IS_TRUE(trust(L"%LOCALAPPDATA%\\Microsoft\\WindowsApps\\pwsh.exe"));
|
||||||
|
VERIFY_IS_TRUE(trust(L"%ProgramFiles%\\PowerShell\\10\\pwsh.exe"));
|
||||||
|
VERIFY_IS_TRUE(trust(L"%ProgramFiles%\\PowerShell\\7.1.5\\pwsh.exe"));
|
||||||
|
|
||||||
|
Log::Comment(L"These are sneaky things that _shouldn't_ be trusted");
|
||||||
|
VERIFY_IS_FALSE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe bad-stuff pwsh.exe"));
|
||||||
|
VERIFY_IS_FALSE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe bad-stuff c:\\pwsh.exe"));
|
||||||
|
VERIFY_IS_FALSE(trust(L"%ProgramFiles%\\PowerShell\\7\\pwsh.exe bad-stuff c:\\ %ProgramFiles%\\PowerShell\\7\\pwsh.exe"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,8 +67,12 @@ namespace winrt::TerminalApp::implementation
|
||||||
// - <none>
|
// - <none>
|
||||||
void TerminalPage::_EndPreviewColorScheme()
|
void TerminalPage::_EndPreviewColorScheme()
|
||||||
{
|
{
|
||||||
for (const auto& f : _restorePreviewFuncs)
|
// Apply the reverts in reverse order - If we had multiple previews
|
||||||
|
// stacked on top of each other, then this will ensure the first one in
|
||||||
|
// is the last one out.
|
||||||
|
for (auto i{ _restorePreviewFuncs.rbegin() }; i < _restorePreviewFuncs.rend(); i++)
|
||||||
{
|
{
|
||||||
|
auto f = *i;
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
_restorePreviewFuncs.clear();
|
_restorePreviewFuncs.clear();
|
||||||
|
@ -90,59 +94,18 @@ namespace winrt::TerminalApp::implementation
|
||||||
{
|
{
|
||||||
if (const auto& scheme{ _settings.GlobalSettings().ColorSchemes().TryLookup(args.SchemeName()) })
|
if (const auto& scheme{ _settings.GlobalSettings().ColorSchemes().TryLookup(args.SchemeName()) })
|
||||||
{
|
{
|
||||||
// Clear the saved preview funcs because we don't need to add a restore each time
|
|
||||||
// the preview color changes, we only need to be able to restore the last one.
|
|
||||||
_restorePreviewFuncs.clear();
|
|
||||||
|
|
||||||
_ApplyToActiveControls([&](const auto& control) {
|
_ApplyToActiveControls([&](const auto& control) {
|
||||||
// Get the settings of the focused control and stash them
|
// Stash a copy of the current scheme.
|
||||||
const auto& controlSettings = control.Settings().as<TerminalSettings>();
|
auto originalScheme{ control.ColorScheme() };
|
||||||
// Make sure to recurse up to the root - if you're doing
|
|
||||||
// this while you're currently previewing a SetColorScheme
|
|
||||||
// action, then the parent of the control's settings is _the
|
|
||||||
// last preview TerminalSettings we inserted! We don't want
|
|
||||||
// to save that one!
|
|
||||||
auto originalSettings = controlSettings.GetParent();
|
|
||||||
while (originalSettings.GetParent() != nullptr)
|
|
||||||
{
|
|
||||||
originalSettings = originalSettings.GetParent();
|
|
||||||
}
|
|
||||||
// Create a new child for those settings
|
|
||||||
TerminalSettingsCreateResult fake{ originalSettings };
|
|
||||||
const auto& childStruct = TerminalSettings::CreateWithParent(fake);
|
|
||||||
// Modify the child to have the applied color scheme
|
|
||||||
childStruct.DefaultSettings().ApplyColorScheme(scheme);
|
|
||||||
|
|
||||||
// Insert that new child as the parent of the control's settings
|
// Apply the new scheme.
|
||||||
controlSettings.SetParent(childStruct.DefaultSettings());
|
control.ColorScheme(scheme.ToCoreScheme());
|
||||||
control.UpdateSettings();
|
|
||||||
|
|
||||||
// Take a copy of the inputs, since they are pointers anyways.
|
// Each control will emplace a revert into the
|
||||||
|
// _restorePreviewFuncs for itself.
|
||||||
_restorePreviewFuncs.emplace_back([=]() {
|
_restorePreviewFuncs.emplace_back([=]() {
|
||||||
// Get the runtime settings of the focused control
|
// On dismiss, restore the original scheme.
|
||||||
const auto& controlSettings{ control.Settings().as<TerminalSettings>() };
|
control.ColorScheme(originalScheme);
|
||||||
|
|
||||||
// Get the control's root settings, the ones that we actually
|
|
||||||
// assigned to it.
|
|
||||||
auto parentSettings{ controlSettings.GetParent() };
|
|
||||||
while (parentSettings.GetParent() != nullptr)
|
|
||||||
{
|
|
||||||
parentSettings = parentSettings.GetParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the root settings are the same as the ones we stashed,
|
|
||||||
// then reset the parent of the runtime settings to the stashed
|
|
||||||
// settings. This condition might be false if the settings
|
|
||||||
// hot-reloaded while the palette was open. In that case, we
|
|
||||||
// don't want to reset the settings to what they were _before_
|
|
||||||
// the hot-reload.
|
|
||||||
if (originalSettings == parentSettings)
|
|
||||||
{
|
|
||||||
// Set the original settings as the parent of the control's settings
|
|
||||||
control.Settings().as<TerminalSettings>().SetParent(originalSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
control.UpdateSettings();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
74
src/cascadia/TerminalApp/AdminWarningPlaceholder.cpp
Normal file
74
src/cascadia/TerminalApp/AdminWarningPlaceholder.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
#include "AdminWarningPlaceholder.h"
|
||||||
|
#include "AdminWarningPlaceholder.g.cpp"
|
||||||
|
#include <LibraryResources.h>
|
||||||
|
using namespace winrt::Windows::UI::Xaml;
|
||||||
|
|
||||||
|
namespace winrt::TerminalApp::implementation
|
||||||
|
{
|
||||||
|
AdminWarningPlaceholder::AdminWarningPlaceholder(const winrt::Microsoft::Terminal::Control::TermControl& control, const winrt::hstring& cmdline) :
|
||||||
|
_control{ control },
|
||||||
|
_Commandline{ cmdline }
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
// If the content we're hosting is a TermControl, then use the control's
|
||||||
|
// BG as our BG, to give the impression that it's there, under the
|
||||||
|
// dialog.
|
||||||
|
if (const auto termControl{ control.try_as<winrt::Microsoft::Terminal::Control::TermControl>() })
|
||||||
|
{
|
||||||
|
RootGrid().Background(termControl.BackgroundBrush());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void AdminWarningPlaceholder::_primaryButtonClick(winrt::Windows::Foundation::IInspectable const& /*sender*/,
|
||||||
|
RoutedEventArgs const& e)
|
||||||
|
{
|
||||||
|
_PrimaryButtonClickedHandlers(*this, e);
|
||||||
|
}
|
||||||
|
void AdminWarningPlaceholder::_cancelButtonClick(winrt::Windows::Foundation::IInspectable const& /*sender*/,
|
||||||
|
RoutedEventArgs const& e)
|
||||||
|
{
|
||||||
|
_CancelButtonClickedHandlers(*this, e);
|
||||||
|
}
|
||||||
|
winrt::Windows::UI::Xaml::Controls::UserControl AdminWarningPlaceholder::Control()
|
||||||
|
{
|
||||||
|
return _control;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Move the focus to the cancel button by default. This has the LOAD
|
||||||
|
// BEARING side effect of also triggering Narrator to read out the
|
||||||
|
// contents of the dialog. It's unclear why doing this works, but it does.
|
||||||
|
// - Using a LayoutUpdated event to trigger the focus change when we're
|
||||||
|
// added to the UI tree did not seem to work.
|
||||||
|
// - Whoever is adding us to the UI tree is responsible for calling this!
|
||||||
|
// Arguments:
|
||||||
|
// - <none>
|
||||||
|
// Return Value:
|
||||||
|
// - <none>
|
||||||
|
void AdminWarningPlaceholder::FocusOnLaunch()
|
||||||
|
{
|
||||||
|
CancelButton().Focus(FocusState::Programmatic);
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::hstring AdminWarningPlaceholder::ControlName()
|
||||||
|
{
|
||||||
|
return RS_(L"AdminWarningPlaceholderName");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdminWarningPlaceholder::_keyUpHandler(IInspectable const& /*sender*/,
|
||||||
|
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
||||||
|
{
|
||||||
|
// If the user presses escape, close the dialog (without confirming)
|
||||||
|
const auto key = e.OriginalKey();
|
||||||
|
if (key == winrt::Windows::System::VirtualKey::Escape)
|
||||||
|
{
|
||||||
|
_CancelButtonClickedHandlers(*this, e);
|
||||||
|
e.Handled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
src/cascadia/TerminalApp/AdminWarningPlaceholder.h
Normal file
51
src/cascadia/TerminalApp/AdminWarningPlaceholder.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) Microsoft Corporation
|
||||||
|
Licensed under the MIT license.
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
- AdminWarningPlaceholder
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
- The AdminWarningPlaceholder is a control used to fill space in a pane and
|
||||||
|
present a warning to the user. It holds on to a real control that it should be
|
||||||
|
replaced with. It looks just like a ContentDialog, except it exists per-pane,
|
||||||
|
whereas a ContentDialog can only be added to take up the whole window.
|
||||||
|
- The caller should make sure to bind our PrimaryButtonClicked and
|
||||||
|
CancelButtonClicked events, to be informed as to which was pressed.
|
||||||
|
|
||||||
|
Author(s):
|
||||||
|
- Mike Griese - September 2021
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AdminWarningPlaceholder.g.h"
|
||||||
|
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||||
|
|
||||||
|
namespace winrt::TerminalApp::implementation
|
||||||
|
{
|
||||||
|
struct AdminWarningPlaceholder : AdminWarningPlaceholderT<AdminWarningPlaceholder>
|
||||||
|
{
|
||||||
|
AdminWarningPlaceholder(const winrt::Microsoft::Terminal::Control::TermControl& control, const winrt::hstring& cmdline);
|
||||||
|
void FocusOnLaunch();
|
||||||
|
winrt::Windows::UI::Xaml::Controls::UserControl Control();
|
||||||
|
winrt::hstring ControlName();
|
||||||
|
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||||
|
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Commandline, _PropertyChangedHandlers);
|
||||||
|
TYPED_EVENT(PrimaryButtonClicked, TerminalApp::AdminWarningPlaceholder, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||||
|
TYPED_EVENT(CancelButtonClicked, TerminalApp::AdminWarningPlaceholder, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend struct AdminWarningPlaceholderT<AdminWarningPlaceholder>; // friend our parent so it can bind private event handlers
|
||||||
|
|
||||||
|
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
|
||||||
|
|
||||||
|
void _primaryButtonClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||||
|
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||||
|
void _cancelButtonClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||||
|
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||||
|
void _keyUpHandler(Windows::Foundation::IInspectable const& sender,
|
||||||
|
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||||
|
};
|
||||||
|
}
|
12
src/cascadia/TerminalApp/AdminWarningPlaceholder.idl
Normal file
12
src/cascadia/TerminalApp/AdminWarningPlaceholder.idl
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace TerminalApp
|
||||||
|
{
|
||||||
|
[default_interface] runtimeclass AdminWarningPlaceholder : Windows.UI.Xaml.Controls.UserControl,
|
||||||
|
Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
String Commandline { get; };
|
||||||
|
String ControlName { get; };
|
||||||
|
}
|
||||||
|
}
|
97
src/cascadia/TerminalApp/AdminWarningPlaceholder.xaml
Normal file
97
src/cascadia/TerminalApp/AdminWarningPlaceholder.xaml
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<!--
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||||
|
the MIT License. See LICENSE in the project root for license information.
|
||||||
|
-->
|
||||||
|
<UserControl x:Class="TerminalApp.AdminWarningPlaceholder"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="using:TerminalApp"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||||
|
AutomationProperties.AccessibilityView="Content"
|
||||||
|
AutomationProperties.IsDialog="True"
|
||||||
|
AutomationProperties.Name="{x:Bind ControlName, Mode=OneWay}"
|
||||||
|
PreviewKeyUp="_keyUpHandler"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
We have to use two grids to be tricky here:
|
||||||
|
- The outer grid will get its background from the control it hosts, and
|
||||||
|
expands to fit its container. This will make it look like the background
|
||||||
|
fills the space available.
|
||||||
|
- The inner grid is set to Center,Center, so that the "dialog" appears
|
||||||
|
centered
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Grid x:Name="RootGrid"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
|
<Grid HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center">
|
||||||
|
<Border Margin="8,8,8,8"
|
||||||
|
Padding="16,8,16,8"
|
||||||
|
AllowFocusOnInteraction="True"
|
||||||
|
AutomationProperties.AccessibilityView="Raw"
|
||||||
|
AutomationProperties.IsDialog="True"
|
||||||
|
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
|
||||||
|
BorderBrush="{ThemeResource SystemAccentColor}"
|
||||||
|
BorderThickness="2,2,2,2"
|
||||||
|
CornerRadius="{ThemeResource OverlayCornerRadius}">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBlock x:Name="ApproveCommandlineWarningTitle"
|
||||||
|
x:Uid="ApproveCommandlineWarningTitle"
|
||||||
|
Padding="0,0,0,16"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="Normal"
|
||||||
|
IsTextSelectionEnabled="True"
|
||||||
|
TextWrapping="WrapWholeWords" />
|
||||||
|
|
||||||
|
<TextBlock x:Name="PrefixTextBlock"
|
||||||
|
x:Uid="ApproveCommandlineWarningPrefixTextBlock"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
IsTextSelectionEnabled="True"
|
||||||
|
TextWrapping="WrapWholeWords" />
|
||||||
|
|
||||||
|
<TextBlock x:Name="CommandlineText"
|
||||||
|
Margin="0,16,0,16"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
FontFamily="Cascadia Mono"
|
||||||
|
IsTextSelectionEnabled="True"
|
||||||
|
Text="{x:Bind Commandline, Mode=OneWay}"
|
||||||
|
TextWrapping="WrapWholeWords" />
|
||||||
|
|
||||||
|
<TextBlock x:Name="SuffixTextBlock"
|
||||||
|
x:Uid="ApproveCommandlineWarningSuffixTextBlock"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
IsTextSelectionEnabled="True"
|
||||||
|
TextWrapping="WrapWholeWords" />
|
||||||
|
<Grid Margin="0,8,0,8"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
XYFocusKeyboardNavigation="Enabled">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button x:Name="PrimaryButton"
|
||||||
|
x:Uid="ApproveCommandlineWarning_PrimaryButton"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Click="_primaryButtonClick"
|
||||||
|
IsTabStop="True"
|
||||||
|
Style="{StaticResource AccentButtonStyle}" />
|
||||||
|
<Button x:Name="CancelButton"
|
||||||
|
x:Uid="ApproveCommandlineWarning_CancelButton"
|
||||||
|
Grid.Column="1"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Click="_cancelButtonClick"
|
||||||
|
IsTabStop="True" />
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
|
@ -451,28 +451,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
if (const auto scheme = _settings.GlobalSettings().ColorSchemes().TryLookup(realArgs.SchemeName()))
|
if (const auto scheme = _settings.GlobalSettings().ColorSchemes().TryLookup(realArgs.SchemeName()))
|
||||||
{
|
{
|
||||||
const auto res = _ApplyToActiveControls([&](auto& control) {
|
const auto res = _ApplyToActiveControls([&](auto& control) {
|
||||||
// Start by getting the current settings of the control
|
control.ColorScheme(scheme.ToCoreScheme());
|
||||||
auto controlSettings = control.Settings().as<TerminalSettings>();
|
|
||||||
auto parentSettings = controlSettings;
|
|
||||||
// Those are the _runtime_ settings however. What we
|
|
||||||
// need to do is:
|
|
||||||
//
|
|
||||||
// 1. Blow away any colors set in the runtime settings.
|
|
||||||
// 2. Apply the color scheme to the parent settings.
|
|
||||||
//
|
|
||||||
// 1 is important to make sure that the effects of
|
|
||||||
// something like `colortool` are cleared when setting
|
|
||||||
// the scheme.
|
|
||||||
if (controlSettings.GetParent() != nullptr)
|
|
||||||
{
|
|
||||||
parentSettings = controlSettings.GetParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyColorScheme(nullptr) will clear the old color scheme.
|
|
||||||
controlSettings.ApplyColorScheme(nullptr);
|
|
||||||
parentSettings.ApplyColorScheme(scheme);
|
|
||||||
|
|
||||||
control.UpdateSettings();
|
|
||||||
});
|
});
|
||||||
args.Handled(res);
|
args.Handled(res);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,67 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
//
|
|
||||||
// MinMaxCloseControl.xaml.cpp
|
|
||||||
// Implementation of the MinMaxCloseControl class
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
#include "MinMaxCloseControl.h"
|
#include "MinMaxCloseControl.h"
|
||||||
|
|
||||||
#include "MinMaxCloseControl.g.cpp"
|
#include "MinMaxCloseControl.g.cpp"
|
||||||
|
|
||||||
#include <LibraryResources.h>
|
#include <LibraryResources.h>
|
||||||
|
|
||||||
using namespace winrt::Windows::UI::Xaml;
|
using namespace winrt::Windows::UI::Xaml;
|
||||||
|
|
||||||
namespace winrt::TerminalApp::implementation
|
namespace winrt::TerminalApp::implementation
|
||||||
{
|
{
|
||||||
|
static void closeToolTipForButton(const Controls::Button& button)
|
||||||
|
{
|
||||||
|
if (auto tt{ Controls::ToolTipService::GetToolTip(button) })
|
||||||
|
{
|
||||||
|
if (auto tooltip{ tt.try_as<Controls::ToolTip>() })
|
||||||
|
{
|
||||||
|
tooltip.IsOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MinMaxCloseControl::MinMaxCloseControl()
|
MinMaxCloseControl::MinMaxCloseControl()
|
||||||
{
|
{
|
||||||
|
// Get our dispatcher. This will get us the same dispatcher as
|
||||||
|
// Dispatcher(), but it's a DispatcherQueue, so we can use it with
|
||||||
|
// ThrottledFunc
|
||||||
|
auto dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
// Get the tooltip hover time from the system, or default to 400ms
|
||||||
|
// (which should be the default, see:
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-trackmouseevent#remarks)
|
||||||
|
unsigned int hoverTimeoutMillis{ 400 };
|
||||||
|
LOG_IF_WIN32_BOOL_FALSE(SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hoverTimeoutMillis, 0));
|
||||||
|
const auto toolTipInterval = std::chrono::milliseconds(hoverTimeoutMillis);
|
||||||
|
|
||||||
|
// Create a ThrottledFunc for opening the tooltip after the hover
|
||||||
|
// timeout. If we hover another button, we should make sure to call
|
||||||
|
// Run() with the new button. Calling `_displayToolTip.Run(nullptr)`,
|
||||||
|
// which will cause us to not display a tooltip, which is used when we
|
||||||
|
// leave the control entirely.
|
||||||
|
_displayToolTip = std::make_shared<ThrottledFuncTrailing<Controls::Button>>(
|
||||||
|
dispatcher,
|
||||||
|
toolTipInterval,
|
||||||
|
[weakThis = get_weak()](Controls::Button button) {
|
||||||
|
// If we provide a button, then open the tooltip on that button.
|
||||||
|
// We can "dismiss" this throttled func by calling it with null,
|
||||||
|
// which will cause us to do nothing at the end of the timeout
|
||||||
|
// instead.
|
||||||
|
if (button)
|
||||||
|
{
|
||||||
|
if (auto tt{ Controls::ToolTipService::GetToolTip(button) })
|
||||||
|
{
|
||||||
|
if (auto tooltip{ tt.try_as<Controls::ToolTip>() })
|
||||||
|
{
|
||||||
|
tooltip.IsOpen(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// These event handlers simply forward each buttons click events up to the
|
// These event handlers simply forward each buttons click events up to the
|
||||||
|
@ -95,4 +137,104 @@ namespace winrt::TerminalApp::implementation
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Called when the mouse hovers a button.
|
||||||
|
// - Transition that button to `PointerOver`
|
||||||
|
// - run the throttled func with this button, to display the tooltip after
|
||||||
|
// a timeout
|
||||||
|
// - dismiss any open tooltips on other buttons.
|
||||||
|
// Arguments:
|
||||||
|
// - button: the button that was hovered
|
||||||
|
void MinMaxCloseControl::HoverButton(CaptionButton button)
|
||||||
|
{
|
||||||
|
// Keep track of the button that's been pressed. we get a mouse move
|
||||||
|
// message when we open the tooltip. If we move the mouse on top of this
|
||||||
|
// button, that we've already pressed, then no need to move to the
|
||||||
|
// "hovered" state, we should stay in the pressed state.
|
||||||
|
if (_lastPressedButton && _lastPressedButton.value() == button)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
// Make sure to use true for the useTransitions parameter, to
|
||||||
|
// animate the fade in/out transition between colors.
|
||||||
|
case CaptionButton::Minimize:
|
||||||
|
VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", true);
|
||||||
|
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||||
|
|
||||||
|
_displayToolTip->Run(MinimizeButton());
|
||||||
|
closeToolTipForButton(MaximizeButton());
|
||||||
|
closeToolTipForButton(CloseButton());
|
||||||
|
break;
|
||||||
|
case CaptionButton::Maximize:
|
||||||
|
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", true);
|
||||||
|
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||||
|
|
||||||
|
closeToolTipForButton(MinimizeButton());
|
||||||
|
_displayToolTip->Run(MaximizeButton());
|
||||||
|
closeToolTipForButton(CloseButton());
|
||||||
|
break;
|
||||||
|
case CaptionButton::Close:
|
||||||
|
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(CloseButton(), L"PointerOver", true);
|
||||||
|
|
||||||
|
closeToolTipForButton(MinimizeButton());
|
||||||
|
closeToolTipForButton(MaximizeButton());
|
||||||
|
_displayToolTip->Run(CloseButton());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Called when the mouse presses down on a button. NOT when it is
|
||||||
|
// released. That's handled one level above, in
|
||||||
|
// TitleBarControl::ReleaseButtons
|
||||||
|
// - Transition that button to `Pressed`
|
||||||
|
// Arguments:
|
||||||
|
// - button: the button that was pressed
|
||||||
|
void MinMaxCloseControl::PressButton(CaptionButton button)
|
||||||
|
{
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case CaptionButton::Minimize:
|
||||||
|
VisualStateManager::GoToState(MinimizeButton(), L"Pressed", true);
|
||||||
|
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||||
|
break;
|
||||||
|
case CaptionButton::Maximize:
|
||||||
|
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(MaximizeButton(), L"Pressed", true);
|
||||||
|
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||||
|
break;
|
||||||
|
case CaptionButton::Close:
|
||||||
|
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(CloseButton(), L"Pressed", true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_lastPressedButton = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Called when buttons are no longer hovered or pressed. Return them all
|
||||||
|
// to the normal state, and dismiss the tooltips.
|
||||||
|
void MinMaxCloseControl::ReleaseButtons()
|
||||||
|
{
|
||||||
|
_displayToolTip->Run(nullptr);
|
||||||
|
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
|
||||||
|
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
|
||||||
|
|
||||||
|
closeToolTipForButton(MinimizeButton());
|
||||||
|
closeToolTipForButton(MaximizeButton());
|
||||||
|
closeToolTipForButton(CloseButton());
|
||||||
|
|
||||||
|
_lastPressedButton = std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "winrt/Windows.UI.Xaml.h"
|
|
||||||
#include "winrt/Windows.UI.Xaml.Markup.h"
|
|
||||||
#include "winrt/Windows.UI.Xaml.Interop.h"
|
|
||||||
#include "MinMaxCloseControl.g.h"
|
#include "MinMaxCloseControl.g.h"
|
||||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||||
|
#include <ThrottledFunc.h>
|
||||||
|
|
||||||
namespace winrt::TerminalApp::implementation
|
namespace winrt::TerminalApp::implementation
|
||||||
{
|
{
|
||||||
|
@ -20,6 +18,10 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
void SetWindowVisualState(WindowVisualState visualState);
|
void SetWindowVisualState(WindowVisualState visualState);
|
||||||
|
|
||||||
|
void HoverButton(CaptionButton button);
|
||||||
|
void PressButton(CaptionButton button);
|
||||||
|
void ReleaseButtons();
|
||||||
|
|
||||||
void _MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
void _MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||||
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
|
||||||
void _MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
void _MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender,
|
||||||
|
@ -30,6 +32,9 @@ namespace winrt::TerminalApp::implementation
|
||||||
TYPED_EVENT(MinimizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
TYPED_EVENT(MinimizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||||
TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||||
TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||||
|
|
||||||
|
std::shared_ptr<ThrottledFuncTrailing<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
|
||||||
|
std::optional<CaptionButton> _lastPressedButton{ std::nullopt };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,10 @@ namespace TerminalApp
|
||||||
|
|
||||||
void SetWindowVisualState(WindowVisualState visualState);
|
void SetWindowVisualState(WindowVisualState visualState);
|
||||||
|
|
||||||
|
void HoverButton(CaptionButton button);
|
||||||
|
void PressButton(CaptionButton button);
|
||||||
|
void ReleaseButtons();
|
||||||
|
|
||||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MinimizeClick;
|
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MinimizeClick;
|
||||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MaximizeClick;
|
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MaximizeClick;
|
||||||
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> CloseClick;
|
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> CloseClick;
|
||||||
|
|
|
@ -220,7 +220,7 @@
|
||||||
</StackPanel.Resources>
|
</StackPanel.Resources>
|
||||||
|
|
||||||
<Button x:Name="MinimizeButton"
|
<Button x:Name="MinimizeButton"
|
||||||
x:Uid="WindowMinimizeButton"
|
x:Uid="MinimizeButton"
|
||||||
Width="46.0"
|
Width="46.0"
|
||||||
Height="{StaticResource CaptionButtonHeightWindowed}"
|
Height="{StaticResource CaptionButtonHeightWindowed}"
|
||||||
MinWidth="46.0"
|
MinWidth="46.0"
|
||||||
|
@ -232,9 +232,14 @@
|
||||||
<x:String x:Key="CaptionButtonPath">M 0 0 H 10</x:String>
|
<x:String x:Key="CaptionButtonPath">M 0 0 H 10</x:String>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Button.Resources>
|
</Button.Resources>
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip>
|
||||||
|
<TextBlock x:Uid="WindowMinimizeButtonToolTip" />
|
||||||
|
</ToolTip>
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
</Button>
|
</Button>
|
||||||
<Button x:Name="MaximizeButton"
|
<Button x:Name="MaximizeButton"
|
||||||
x:Uid="WindowMaximizeButton"
|
x:Uid="MaximizeButton"
|
||||||
Width="46.0"
|
Width="46.0"
|
||||||
Height="{StaticResource CaptionButtonHeightWindowed}"
|
Height="{StaticResource CaptionButtonHeightWindowed}"
|
||||||
MinWidth="46.0"
|
MinWidth="46.0"
|
||||||
|
@ -256,7 +261,7 @@
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
</Button>
|
</Button>
|
||||||
<Button x:Name="CloseButton"
|
<Button x:Name="CloseButton"
|
||||||
x:Uid="WindowCloseButton"
|
x:Uid="CloseButton"
|
||||||
Width="46.0"
|
Width="46.0"
|
||||||
Height="{StaticResource CaptionButtonHeightWindowed}"
|
Height="{StaticResource CaptionButtonHeightWindowed}"
|
||||||
MinWidth="46.0"
|
MinWidth="46.0"
|
||||||
|
@ -309,5 +314,10 @@
|
||||||
<x:String x:Key="CaptionButtonPath">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
<x:String x:Key="CaptionButtonPath">M 0 0 L 10 10 M 10 0 L 0 10</x:String>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Button.Resources>
|
</Button.Resources>
|
||||||
|
<ToolTipService.ToolTip>
|
||||||
|
<ToolTip>
|
||||||
|
<TextBlock x:Uid="WindowCloseButtonToolTip" />
|
||||||
|
</ToolTip>
|
||||||
|
</ToolTipService.ToolTip>
|
||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
@ -34,7 +34,7 @@ static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Wi
|
||||||
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_focusedBorderBrush = { nullptr };
|
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_focusedBorderBrush = { nullptr };
|
||||||
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_unfocusedBorderBrush = { nullptr };
|
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::s_unfocusedBorderBrush = { nullptr };
|
||||||
|
|
||||||
Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFocused) :
|
Pane::Pane(const Profile& profile, const Controls::UserControl& control, const bool lastFocused) :
|
||||||
_control{ control },
|
_control{ control },
|
||||||
_lastActive{ lastFocused },
|
_lastActive{ lastFocused },
|
||||||
_profile{ profile }
|
_profile{ profile }
|
||||||
|
@ -42,8 +42,11 @@ Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFo
|
||||||
_root.Children().Append(_borderFirst);
|
_root.Children().Append(_borderFirst);
|
||||||
_borderFirst.Child(_control);
|
_borderFirst.Child(_control);
|
||||||
|
|
||||||
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
|
if (const auto& termControl{ _control.try_as<TermControl>() })
|
||||||
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
|
{
|
||||||
|
_connectionStateChangedToken = termControl.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
|
||||||
|
_warningBellToken = termControl.WarningBell({ this, &Pane::_ControlWarningBellHandler });
|
||||||
|
}
|
||||||
|
|
||||||
// On the first Pane's creation, lookup resources we'll use to theme the
|
// On the first Pane's creation, lookup resources we'll use to theme the
|
||||||
// Pane, including the brushed to use for the focused/unfocused border
|
// Pane, including the brushed to use for the focused/unfocused border
|
||||||
|
@ -125,11 +128,23 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
|
||||||
assert(_IsLeaf());
|
assert(_IsLeaf());
|
||||||
|
|
||||||
NewTerminalArgs args{};
|
NewTerminalArgs args{};
|
||||||
auto controlSettings = _control.Settings().as<TerminalSettings>();
|
auto termControl{ _control.try_as<TermControl>() };
|
||||||
|
if (!termControl)
|
||||||
|
{
|
||||||
|
if (auto adminWarning{ _control.try_as<AdminWarningPlaceholder>() })
|
||||||
|
{
|
||||||
|
termControl = adminWarning.Content().try_as<TermControl>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!termControl)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto controlSettings = termControl.Settings();
|
||||||
|
|
||||||
args.Profile(controlSettings.ProfileName());
|
args.Profile(controlSettings.ProfileName());
|
||||||
// If we know the user's working directory use it instead of the profile.
|
// If we know the user's working directory use it instead of the profile.
|
||||||
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
|
if (const auto dir = termControl.WorkingDirectory(); !dir.empty())
|
||||||
{
|
{
|
||||||
args.StartingDirectory(dir);
|
args.StartingDirectory(dir);
|
||||||
}
|
}
|
||||||
|
@ -156,16 +171,13 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
|
||||||
args.TabColor(winrt::Windows::Foundation::IReference<winrt::Windows::UI::Color>(c));
|
args.TabColor(winrt::Windows::Foundation::IReference<winrt::Windows::UI::Color>(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controlSettings.AppliedColorScheme())
|
// TODO:GH#9800 - we used to be able to persist the color scheme that a
|
||||||
{
|
// TermControl was initialized with, by name. With the change to having the
|
||||||
auto name = controlSettings.AppliedColorScheme().Name();
|
// control own its own copy of its settings, this isn't possible anymore.
|
||||||
// Only save the color scheme if it is different than the profile color
|
//
|
||||||
// scheme to not override any other profile appearance choices.
|
// We may be able to get around this by storing the Name in the Core::Scheme
|
||||||
if (_profile.DefaultAppearance().ColorSchemeName() != name)
|
// object. That would work for schemes set by the Terminal, but not ones set
|
||||||
{
|
// by VT, but that seems good enough.
|
||||||
args.ColorScheme(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
@ -832,6 +844,40 @@ bool Pane::SwapPanes(std::shared_ptr<Pane> first, std::shared_ptr<Pane> second)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Controls::UserControl Pane::ReplaceControl(const Controls::UserControl& control)
|
||||||
|
{
|
||||||
|
if (!_IsLeaf())
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove old control's event handlers
|
||||||
|
const auto& oldControl = _control;
|
||||||
|
_gotFocusRevoker.revoke();
|
||||||
|
_lostFocusRevoker.revoke();
|
||||||
|
if (const auto& oldTermControl{ _control.try_as<TermControl>() })
|
||||||
|
{
|
||||||
|
oldTermControl.ConnectionStateChanged(_connectionStateChangedToken);
|
||||||
|
oldTermControl.WarningBell(_warningBellToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
_control = control;
|
||||||
|
|
||||||
|
_borderFirst.Child(_control);
|
||||||
|
|
||||||
|
// Register an event with the control to have it inform us when it gains focus.
|
||||||
|
_gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler });
|
||||||
|
_lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler });
|
||||||
|
|
||||||
|
if (const auto& termControl{ _control.try_as<TermControl>() })
|
||||||
|
{
|
||||||
|
_connectionStateChangedToken = termControl.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
|
||||||
|
_warningBellToken = termControl.WarningBell({ this, &Pane::_ControlWarningBellHandler });
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldControl;
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Given two panes' offsets, test whether the `direction` side of first is adjacent to second.
|
// - Given two panes' offsets, test whether the `direction` side of first is adjacent to second.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
@ -1079,8 +1125,12 @@ void Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundatio
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto& termControl{ _control.try_as<TermControl>() };
|
||||||
const auto newConnectionState = _control.ConnectionState();
|
if (!termControl)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto newConnectionState = termControl.ConnectionState();
|
||||||
const auto previousConnectionState = std::exchange(_connectionState, newConnectionState);
|
const auto previousConnectionState = std::exchange(_connectionState, newConnectionState);
|
||||||
|
|
||||||
if (newConnectionState < ConnectionState::Closed)
|
if (newConnectionState < ConnectionState::Closed)
|
||||||
|
@ -1123,7 +1173,9 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_profile)
|
|
||||||
|
const auto& termControl{ _control.try_as<TermControl>() };
|
||||||
|
if (_profile && termControl)
|
||||||
{
|
{
|
||||||
// We don't want to do anything if nothing is set, so check for that first
|
// We don't want to do anything if nothing is set, so check for that first
|
||||||
if (static_cast<int>(_profile.BellStyle()) != 0)
|
if (static_cast<int>(_profile.BellStyle()) != 0)
|
||||||
|
@ -1137,7 +1189,7 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
|
||||||
|
|
||||||
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
|
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
|
||||||
{
|
{
|
||||||
_control.BellLightOn();
|
termControl.BellLightOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
// raise the event with the bool value corresponding to the taskbar flag
|
// raise the event with the bool value corresponding to the taskbar flag
|
||||||
|
@ -1197,7 +1249,11 @@ void Pane::Shutdown()
|
||||||
std::unique_lock lock{ _createCloseLock };
|
std::unique_lock lock{ _createCloseLock };
|
||||||
if (_IsLeaf())
|
if (_IsLeaf())
|
||||||
{
|
{
|
||||||
_control.Close();
|
const auto& termControl{ _control.try_as<TermControl>() };
|
||||||
|
if (termControl)
|
||||||
|
{
|
||||||
|
termControl.Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1207,7 +1263,7 @@ void Pane::Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Get the root UIElement of this pane. There may be a single TermControl as a
|
// - Get the root UIElement of this pane. There may be a single UserControl as a
|
||||||
// child, or an entire tree of grids and panes as children of this element.
|
// child, or an entire tree of grids and panes as children of this element.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - <none>
|
// - <none>
|
||||||
|
@ -1266,7 +1322,7 @@ TermControl Pane::GetLastFocusedTerminalControl()
|
||||||
{
|
{
|
||||||
if (p->_IsLeaf())
|
if (p->_IsLeaf())
|
||||||
{
|
{
|
||||||
return p->_control;
|
return p->GetTerminalControl();
|
||||||
}
|
}
|
||||||
pane = p;
|
pane = p;
|
||||||
}
|
}
|
||||||
|
@ -1274,7 +1330,7 @@ TermControl Pane::GetLastFocusedTerminalControl()
|
||||||
}
|
}
|
||||||
return _firstChild->GetLastFocusedTerminalControl();
|
return _firstChild->GetLastFocusedTerminalControl();
|
||||||
}
|
}
|
||||||
return _control;
|
return GetTerminalControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -1283,8 +1339,15 @@ TermControl Pane::GetLastFocusedTerminalControl()
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - <none>
|
// - <none>
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - nullptr if this Pane is a parent, otherwise the TermControl of this Pane.
|
// - nullptr if this Pane is a parent or isn't hosting a Terminal, otherwise the
|
||||||
TermControl Pane::GetTerminalControl()
|
// TermControl of this Pane.
|
||||||
|
TermControl Pane::GetTerminalControl() const
|
||||||
|
{
|
||||||
|
auto control{ GetUserControl() };
|
||||||
|
return control ? control.try_as<TermControl>() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Controls::UserControl Pane::GetUserControl() const
|
||||||
{
|
{
|
||||||
return _IsLeaf() ? _control : nullptr;
|
return _IsLeaf() ? _control : nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1457,23 +1520,13 @@ void Pane::_FocusFirstChild()
|
||||||
void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Profile& profile)
|
void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Profile& profile)
|
||||||
{
|
{
|
||||||
assert(_IsLeaf());
|
assert(_IsLeaf());
|
||||||
|
const auto& termControl{ _control.try_as<TermControl>() };
|
||||||
_profile = profile;
|
if (!termControl)
|
||||||
auto controlSettings = _control.Settings().as<TerminalSettings>();
|
|
||||||
// Update the parent of the control's settings object (and not the object itself) so
|
|
||||||
// that any overrides made by the control don't get affected by the reload
|
|
||||||
controlSettings.SetParent(settings.DefaultSettings());
|
|
||||||
auto unfocusedSettings{ settings.UnfocusedSettings() };
|
|
||||||
if (unfocusedSettings)
|
|
||||||
{
|
{
|
||||||
// Note: the unfocused settings needs to be entirely unchanged _except_ we need to
|
return;
|
||||||
// set its parent to the settings object that lives in the control. This is because
|
|
||||||
// the overrides made by the control live in that settings object, so we want to make
|
|
||||||
// sure the unfocused settings inherit from that.
|
|
||||||
unfocusedSettings.SetParent(controlSettings);
|
|
||||||
}
|
}
|
||||||
_control.UnfocusedAppearance(unfocusedSettings);
|
_profile = profile;
|
||||||
_control.UpdateSettings();
|
termControl.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -1614,8 +1667,12 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||||
_id = remainingChild->Id();
|
_id = remainingChild->Id();
|
||||||
|
|
||||||
// Add our new event handler before revoking the old one.
|
// Add our new event handler before revoking the old one.
|
||||||
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
|
const auto& termControl{ _control.try_as<TermControl>() };
|
||||||
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
|
if (termControl)
|
||||||
|
{
|
||||||
|
_connectionStateChangedToken = termControl.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
|
||||||
|
_warningBellToken = termControl.WarningBell({ this, &Pane::_ControlWarningBellHandler });
|
||||||
|
}
|
||||||
|
|
||||||
// Revoke the old event handlers. Remove both the handlers for the panes
|
// Revoke the old event handlers. Remove both the handlers for the panes
|
||||||
// themselves closing, and remove their handlers for their controls
|
// themselves closing, and remove their handlers for their controls
|
||||||
|
@ -1629,8 +1686,11 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||||
closedChild->WalkTree([](auto p) {
|
closedChild->WalkTree([](auto p) {
|
||||||
if (p->_IsLeaf())
|
if (p->_IsLeaf())
|
||||||
{
|
{
|
||||||
p->_control.ConnectionStateChanged(p->_connectionStateChangedToken);
|
if (const auto& closedControl{ p->_control.try_as<TermControl>() })
|
||||||
p->_control.WarningBell(p->_warningBellToken);
|
{
|
||||||
|
closedControl.ConnectionStateChanged(p->_connectionStateChangedToken);
|
||||||
|
closedControl.WarningBell(p->_warningBellToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -1638,15 +1698,19 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||||
|
|
||||||
closedChild->Closed(closedChildClosedToken);
|
closedChild->Closed(closedChildClosedToken);
|
||||||
remainingChild->Closed(remainingChildClosedToken);
|
remainingChild->Closed(remainingChildClosedToken);
|
||||||
remainingChild->_control.ConnectionStateChanged(remainingChild->_connectionStateChangedToken);
|
|
||||||
remainingChild->_control.WarningBell(remainingChild->_warningBellToken);
|
if (const auto& remainingControl{ remainingChild->_control.try_as<TermControl>() })
|
||||||
|
{
|
||||||
|
remainingControl.ConnectionStateChanged(remainingChild->_connectionStateChangedToken);
|
||||||
|
remainingControl.WarningBell(remainingChild->_warningBellToken);
|
||||||
|
}
|
||||||
|
|
||||||
// If we or either of our children was focused, we want to take that
|
// If we or either of our children was focused, we want to take that
|
||||||
// focus from them.
|
// focus from them.
|
||||||
_lastActive = _lastActive || _firstChild->_lastActive || _secondChild->_lastActive;
|
_lastActive = _lastActive || _firstChild->_lastActive || _secondChild->_lastActive;
|
||||||
|
|
||||||
// Remove all the ui elements of the remaining child. This'll make sure
|
// Remove all the ui elements of the remaining child. This'll make sure
|
||||||
// we can re-attach the TermControl to our Grid.
|
// we can re-attach the UserControl to our Grid.
|
||||||
remainingChild->_root.Children().Clear();
|
remainingChild->_root.Children().Clear();
|
||||||
remainingChild->_borderFirst.Child(nullptr);
|
remainingChild->_borderFirst.Child(nullptr);
|
||||||
|
|
||||||
|
@ -1657,7 +1721,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||||
_root.ColumnDefinitions().Clear();
|
_root.ColumnDefinitions().Clear();
|
||||||
_root.RowDefinitions().Clear();
|
_root.RowDefinitions().Clear();
|
||||||
|
|
||||||
// Reattach the TermControl to our grid.
|
// Reattach the UserControl to our grid.
|
||||||
_root.Children().Append(_borderFirst);
|
_root.Children().Append(_borderFirst);
|
||||||
_borderFirst.Child(_control);
|
_borderFirst.Child(_control);
|
||||||
|
|
||||||
|
@ -1719,8 +1783,11 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||||
closedChild->WalkTree([](auto p) {
|
closedChild->WalkTree([](auto p) {
|
||||||
if (p->_IsLeaf())
|
if (p->_IsLeaf())
|
||||||
{
|
{
|
||||||
p->_control.ConnectionStateChanged(p->_connectionStateChangedToken);
|
if (const auto& closedControl{ p->_control.try_as<TermControl>() })
|
||||||
p->_control.WarningBell(p->_warningBellToken);
|
{
|
||||||
|
closedControl.ConnectionStateChanged(p->_connectionStateChangedToken);
|
||||||
|
closedControl.WarningBell(p->_warningBellToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -2467,12 +2534,15 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
|
||||||
std::unique_lock lock{ _createCloseLock };
|
std::unique_lock lock{ _createCloseLock };
|
||||||
|
|
||||||
if (_IsLeaf())
|
if (_IsLeaf())
|
||||||
|
{
|
||||||
|
if (const auto& termControl{ _control.try_as<TermControl>() })
|
||||||
{
|
{
|
||||||
// revoke our handler - the child will take care of the control now.
|
// revoke our handler - the child will take care of the control now.
|
||||||
_control.ConnectionStateChanged(_connectionStateChangedToken);
|
termControl.ConnectionStateChanged(_connectionStateChangedToken);
|
||||||
|
termControl.WarningBell(_warningBellToken);
|
||||||
_connectionStateChangedToken.value = 0;
|
_connectionStateChangedToken.value = 0;
|
||||||
_control.WarningBell(_warningBellToken);
|
|
||||||
_warningBellToken.value = 0;
|
_warningBellToken.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove our old GotFocus handler from the control. We don't want the
|
// Remove our old GotFocus handler from the control. We don't want the
|
||||||
// control telling us that it's now focused, we want it telling its new
|
// control telling us that it's now focused, we want it telling its new
|
||||||
|
@ -2482,7 +2552,7 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any children we currently have. We can't add the existing
|
// Remove any children we currently have. We can't add the existing
|
||||||
// TermControl to a new grid until we do this.
|
// UserControl to a new grid until we do this.
|
||||||
_root.Children().Clear();
|
_root.Children().Clear();
|
||||||
_borderFirst.Child(nullptr);
|
_borderFirst.Child(nullptr);
|
||||||
_borderSecond.Child(nullptr);
|
_borderSecond.Child(nullptr);
|
||||||
|
@ -2860,8 +2930,13 @@ float Pane::CalcSnappedDimension(const bool widthOrHeight, const float dimension
|
||||||
// If requested size is already snapped, then both returned values equal this value.
|
// If requested size is already snapped, then both returned values equal this value.
|
||||||
Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
|
Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
|
||||||
{
|
{
|
||||||
|
const auto& termControl{ _control.try_as<TermControl>() };
|
||||||
if (_IsLeaf())
|
if (_IsLeaf())
|
||||||
{
|
{
|
||||||
|
if (!termControl)
|
||||||
|
{
|
||||||
|
return { dimension, dimension };
|
||||||
|
}
|
||||||
// If we're a leaf pane, align to the grid of controlling terminal
|
// If we're a leaf pane, align to the grid of controlling terminal
|
||||||
|
|
||||||
const auto minSize = _GetMinSize();
|
const auto minSize = _GetMinSize();
|
||||||
|
@ -2872,7 +2947,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
|
||||||
return { minDimension, minDimension };
|
return { minDimension, minDimension };
|
||||||
}
|
}
|
||||||
|
|
||||||
float lower = _control.SnapDimensionToGrid(widthOrHeight, dimension);
|
float lower = termControl.SnapDimensionToGrid(widthOrHeight, dimension);
|
||||||
if (widthOrHeight)
|
if (widthOrHeight)
|
||||||
{
|
{
|
||||||
lower += WI_IsFlagSet(_borders, Borders::Left) ? PaneBorderSize : 0;
|
lower += WI_IsFlagSet(_borders, Borders::Left) ? PaneBorderSize : 0;
|
||||||
|
@ -2892,7 +2967,7 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto cellSize = _control.CharacterDimensions();
|
const auto cellSize = termControl.CharacterDimensions();
|
||||||
const auto higher = lower + (widthOrHeight ? cellSize.Width : cellSize.Height);
|
const auto higher = lower + (widthOrHeight ? cellSize.Width : cellSize.Height);
|
||||||
return { lower, higher };
|
return { lower, higher };
|
||||||
}
|
}
|
||||||
|
@ -2937,7 +3012,10 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
|
||||||
// - <none>
|
// - <none>
|
||||||
void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& sizeNode) const
|
void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& sizeNode) const
|
||||||
{
|
{
|
||||||
|
const auto& termControl{ _control.try_as<TermControl>() };
|
||||||
if (_IsLeaf())
|
if (_IsLeaf())
|
||||||
|
{
|
||||||
|
if (termControl)
|
||||||
{
|
{
|
||||||
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
|
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
|
||||||
// is true, see below).
|
// is true, see below).
|
||||||
|
@ -2952,11 +3030,21 @@ void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& si
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto cellSize = _control.CharacterDimensions();
|
const auto cellSize = termControl.CharacterDimensions();
|
||||||
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
|
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// If we're a leaf that didn't have a TermControl, then just increment
|
||||||
|
// by one. We have to increment by _some_ value, because this is used in
|
||||||
|
// a while() loop to find the next bigger size we can snap to. But since
|
||||||
|
// a non-terminal control doesn't really care what size it's snapped to,
|
||||||
|
// we can just say "one pixel larger is the next snap point"
|
||||||
|
sizeNode.size += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // !_IsLeaf()
|
||||||
{
|
{
|
||||||
// We're a parent pane, so we have to advance dimension of our children panes. In
|
// We're a parent pane, so we have to advance dimension of our children panes. In
|
||||||
// fact, we advance only one child (chosen later) to keep the growth fine-grained.
|
// fact, we advance only one child (chosen later) to keep the growth fine-grained.
|
||||||
|
@ -3058,7 +3146,8 @@ Size Pane::_GetMinSize() const
|
||||||
{
|
{
|
||||||
if (_IsLeaf())
|
if (_IsLeaf())
|
||||||
{
|
{
|
||||||
auto controlSize = _control.MinimumSize();
|
const auto& termControl{ _control.try_as<TermControl>() };
|
||||||
|
auto controlSize = termControl ? termControl.MinimumSize() : Size{ 1, 1 };
|
||||||
auto newWidth = controlSize.Width;
|
auto newWidth = controlSize.Width;
|
||||||
auto newHeight = controlSize.Height;
|
auto newHeight = controlSize.Height;
|
||||||
|
|
||||||
|
@ -3244,7 +3333,10 @@ std::optional<SplitDirection> Pane::PreCalculateAutoSplit(const std::shared_ptr<
|
||||||
// - Returns true if the pane or one of its descendants is read-only
|
// - Returns true if the pane or one of its descendants is read-only
|
||||||
bool Pane::ContainsReadOnly() const
|
bool Pane::ContainsReadOnly() const
|
||||||
{
|
{
|
||||||
return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
|
const auto& termControl{ GetTerminalControl() };
|
||||||
|
return termControl ?
|
||||||
|
termControl.ReadOnly() :
|
||||||
|
(_IsLeaf() ? false : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -3257,13 +3349,14 @@ bool Pane::ContainsReadOnly() const
|
||||||
// - <none>
|
// - <none>
|
||||||
void Pane::CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states)
|
void Pane::CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states)
|
||||||
{
|
{
|
||||||
if (_IsLeaf())
|
const auto& termControl{ GetTerminalControl() };
|
||||||
|
if (termControl)
|
||||||
{
|
{
|
||||||
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_control.TaskbarState(),
|
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(termControl.TaskbarState(),
|
||||||
_control.TaskbarProgress()) };
|
termControl.TaskbarProgress()) };
|
||||||
states.push_back(tbState);
|
states.push_back(tbState);
|
||||||
}
|
}
|
||||||
else
|
else if (!_IsLeaf())
|
||||||
{
|
{
|
||||||
_firstChild->CollectTaskbarStates(states);
|
_firstChild->CollectTaskbarStates(states);
|
||||||
_secondChild->CollectTaskbarStates(states);
|
_secondChild->CollectTaskbarStates(states);
|
||||||
|
|
|
@ -56,7 +56,7 @@ class Pane : public std::enable_shared_from_this<Pane>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Pane(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
Pane(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
||||||
const winrt::Microsoft::Terminal::Control::TermControl& control,
|
const winrt::Windows::UI::Xaml::Controls::UserControl& control,
|
||||||
const bool lastFocused = false);
|
const bool lastFocused = false);
|
||||||
|
|
||||||
Pane(std::shared_ptr<Pane> first,
|
Pane(std::shared_ptr<Pane> first,
|
||||||
|
@ -66,8 +66,9 @@ public:
|
||||||
const bool lastFocused = false);
|
const bool lastFocused = false);
|
||||||
|
|
||||||
std::shared_ptr<Pane> GetActivePane();
|
std::shared_ptr<Pane> GetActivePane();
|
||||||
|
winrt::Windows::UI::Xaml::Controls::UserControl GetUserControl() const;
|
||||||
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
|
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
|
||||||
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
|
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl() const;
|
||||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
|
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -126,6 +127,8 @@ public:
|
||||||
winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType);
|
winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType);
|
||||||
std::shared_ptr<Pane> DetachPane(std::shared_ptr<Pane> pane);
|
std::shared_ptr<Pane> DetachPane(std::shared_ptr<Pane> pane);
|
||||||
|
|
||||||
|
winrt::Windows::UI::Xaml::Controls::UserControl ReplaceControl(const winrt::Windows::UI::Xaml::Controls::UserControl& control);
|
||||||
|
|
||||||
int GetLeafPaneCount() const noexcept;
|
int GetLeafPaneCount() const noexcept;
|
||||||
|
|
||||||
void Maximize(std::shared_ptr<Pane> zoomedPane);
|
void Maximize(std::shared_ptr<Pane> zoomedPane);
|
||||||
|
@ -200,7 +203,8 @@ private:
|
||||||
winrt::Windows::UI::Xaml::Controls::Grid _root{};
|
winrt::Windows::UI::Xaml::Controls::Grid _root{};
|
||||||
winrt::Windows::UI::Xaml::Controls::Border _borderFirst{};
|
winrt::Windows::UI::Xaml::Controls::Border _borderFirst{};
|
||||||
winrt::Windows::UI::Xaml::Controls::Border _borderSecond{};
|
winrt::Windows::UI::Xaml::Controls::Border _borderSecond{};
|
||||||
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
|
winrt::Windows::UI::Xaml::Controls::UserControl _control{ nullptr };
|
||||||
|
|
||||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
|
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
|
||||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
|
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
|
||||||
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_unfocusedBorderBrush;
|
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_unfocusedBorderBrush;
|
||||||
|
|
|
@ -411,6 +411,9 @@
|
||||||
<data name="WindowCloseButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
<data name="WindowCloseButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||||
<value>Close</value>
|
<value>Close</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="WindowCloseButtonToolTip.Text" xml:space="preserve">
|
||||||
|
<value>Close</value>
|
||||||
|
</data>
|
||||||
<data name="WindowMaximizeButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
<data name="WindowMaximizeButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||||
<value>Maximize</value>
|
<value>Maximize</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -420,6 +423,9 @@
|
||||||
<data name="WindowMinimizeButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
<data name="WindowMinimizeButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||||
<value>Minimize</value>
|
<value>Minimize</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="WindowMinimizeButtonToolTip.Text" xml:space="preserve">
|
||||||
|
<value>Minimize</value>
|
||||||
|
</data>
|
||||||
<data name="AboutDialog.Title" xml:space="preserve">
|
<data name="AboutDialog.Title" xml:space="preserve">
|
||||||
<value>About</value>
|
<value>About</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -504,6 +510,24 @@
|
||||||
<data name="MultiLinePasteDialog.Title" xml:space="preserve">
|
<data name="MultiLinePasteDialog.Title" xml:space="preserve">
|
||||||
<value>Warning</value>
|
<value>Warning</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ApproveCommandlineWarningPrefixTextBlock.Text" xml:space="preserve">
|
||||||
|
<value>You are about to execute the following command-line:</value>
|
||||||
|
</data>
|
||||||
|
<data name="ApproveCommandlineWarningSuffixTextBlock.Text" xml:space="preserve">
|
||||||
|
<value>Do you wish to continue?</value>
|
||||||
|
</data>
|
||||||
|
<data name="ApproveCommandlineWarning_PrimaryButton.Content" xml:space="preserve">
|
||||||
|
<value>Allow command-line</value>
|
||||||
|
</data>
|
||||||
|
<data name="ApproveCommandlineWarning_CancelButton.Content" xml:space="preserve">
|
||||||
|
<value>Cancel</value>
|
||||||
|
</data>
|
||||||
|
<data name="ApproveCommandlineWarningTitle.Text" xml:space="preserve">
|
||||||
|
<value>Warning</value>
|
||||||
|
</data>
|
||||||
|
<data name="AdminWarningPlaceholderName" xml:space="preserve">
|
||||||
|
<value>Elevated command-line warning</value>
|
||||||
|
</data>
|
||||||
<data name="CommandPalette_SearchBox.PlaceholderText" xml:space="preserve">
|
<data name="CommandPalette_SearchBox.PlaceholderText" xml:space="preserve">
|
||||||
<value>Type a command name...</value>
|
<value>Type a command name...</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <LibraryResources.h>
|
#include <LibraryResources.h>
|
||||||
|
|
||||||
#include "TabRowControl.h"
|
#include "TabRowControl.h"
|
||||||
|
#include "AdminWarningPlaceholder.h"
|
||||||
#include "ColorHelper.h"
|
#include "ColorHelper.h"
|
||||||
#include "DebugTapConnection.h"
|
#include "DebugTapConnection.h"
|
||||||
#include "SettingsTab.h"
|
#include "SettingsTab.h"
|
||||||
|
|
|
@ -63,6 +63,9 @@
|
||||||
<Page Include="CommandPalette.xaml">
|
<Page Include="CommandPalette.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="AdminWarningPlaceholder.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- ========================= Headers ======================== -->
|
<!-- ========================= Headers ======================== -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -141,6 +144,9 @@
|
||||||
<ClInclude Include="AppLogic.h">
|
<ClInclude Include="AppLogic.h">
|
||||||
<DependentUpon>AppLogic.idl</DependentUpon>
|
<DependentUpon>AppLogic.idl</DependentUpon>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="AdminWarningPlaceholder.h">
|
||||||
|
<DependentUpon>AdminWarningPlaceholder.xaml</DependentUpon>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="Toast.h" />
|
<ClInclude Include="Toast.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- ========================= Cpp Files ======================== -->
|
<!-- ========================= Cpp Files ======================== -->
|
||||||
|
@ -234,6 +240,9 @@
|
||||||
<ClCompile Include="AppLogic.cpp">
|
<ClCompile Include="AppLogic.cpp">
|
||||||
<DependentUpon>AppLogic.idl</DependentUpon>
|
<DependentUpon>AppLogic.idl</DependentUpon>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="AdminWarningPlaceholder.cpp">
|
||||||
|
<DependentUpon>AdminWarningPlaceholder.xaml</DependentUpon>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||||
<ClCompile Include="Toast.cpp" />
|
<ClCompile Include="Toast.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -295,6 +304,10 @@
|
||||||
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
<DependentUpon>CommandPalette.xaml</DependentUpon>
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Midl>
|
</Midl>
|
||||||
|
<Midl Include="AdminWarningPlaceholder.idl">
|
||||||
|
<DependentUpon>AdminWarningPlaceholder.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Midl>
|
||||||
<Midl Include="FilteredCommand.idl" />
|
<Midl Include="FilteredCommand.idl" />
|
||||||
<Midl Include="EmptyStringVisibilityConverter.idl" />
|
<Midl Include="EmptyStringVisibilityConverter.idl" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "DebugTapConnection.h"
|
#include "DebugTapConnection.h"
|
||||||
#include "SettingsTab.h"
|
#include "SettingsTab.h"
|
||||||
#include "RenameWindowRequestedArgs.g.cpp"
|
#include "RenameWindowRequestedArgs.g.cpp"
|
||||||
|
#include "AdminWarningPlaceholder.h"
|
||||||
#include "../inc/WindowingBehavior.h"
|
#include "../inc/WindowingBehavior.h"
|
||||||
|
|
||||||
#include <til/latch.h>
|
#include <til/latch.h>
|
||||||
|
@ -1414,13 +1415,15 @@ namespace winrt::TerminalApp::implementation
|
||||||
void TerminalPage::_Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll)
|
void TerminalPage::_Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll)
|
||||||
{
|
{
|
||||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||||
|
{
|
||||||
|
if (const auto& termControl{ terminalTab->GetActiveTerminalControl() })
|
||||||
{
|
{
|
||||||
uint32_t realRowsToScroll;
|
uint32_t realRowsToScroll;
|
||||||
if (rowsToScroll == nullptr)
|
if (rowsToScroll == nullptr)
|
||||||
{
|
{
|
||||||
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
|
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
|
||||||
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
|
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
|
||||||
terminalTab->GetActiveTerminalControl().ViewHeight() :
|
termControl.ViewHeight() :
|
||||||
_systemRowsToScroll;
|
_systemRowsToScroll;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1432,6 +1435,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
terminalTab->Scroll(scrollDelta);
|
terminalTab->Scroll(scrollDelta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Moves the currently active pane on the currently active tab to the
|
// - Moves the currently active pane on the currently active tab to the
|
||||||
|
@ -1483,6 +1487,246 @@ namespace winrt::TerminalApp::implementation
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function Description:
|
||||||
|
// - Returns true if this commandline is a commandline that we know is safe.
|
||||||
|
// Generally, this is true for any executables in system32. We can use
|
||||||
|
// this to bypass the elevated state check, because we're confident that
|
||||||
|
// executables in that path won't have been hijacked.
|
||||||
|
// - TECHNICALLY a user can take ownership of a file in system32 and
|
||||||
|
// replace it as the system administrator. You could say it's OK though
|
||||||
|
// because you'd already have to have had admin rights to mess that
|
||||||
|
// folder up or something.
|
||||||
|
// - Will attempt to resolve environment strings.
|
||||||
|
// - Will also manually allow commandlines as generated for the default WSL
|
||||||
|
// distros.
|
||||||
|
// - Will also trust %ProgramFiles%\Powershell\...\pwsh.exe paths, for
|
||||||
|
// PowerShell Core.
|
||||||
|
// Arguments:
|
||||||
|
// - commandLine: the command to check.
|
||||||
|
// Return Value (example):
|
||||||
|
// - C:\windows\system32\cmd.exe -> returns true
|
||||||
|
// - cmd.exe -> returns false
|
||||||
|
// - C:\windows\system32\cmd.exe /k echo sneaky sneak -> returns false
|
||||||
|
// - %SystemRoot%\System32\cmd.exe -> returns true
|
||||||
|
// - %SystemRoot%\System32\wsl.exe -d <distro name> -> returns true
|
||||||
|
bool TerminalPage::_isTrustedCommandline(std::wstring_view commandLine)
|
||||||
|
{
|
||||||
|
// use C++11 magic statics to make sure we only do this once.
|
||||||
|
static std::wstring systemDirectory = []() -> std::wstring {
|
||||||
|
// *** THIS IS A SINGLETON ***
|
||||||
|
static std::wstring sys32{};
|
||||||
|
if (FAILED(wil::GetSystemDirectoryW(sys32)))
|
||||||
|
{
|
||||||
|
// we couldn't look up where system32 is?? Then it's definitely not
|
||||||
|
// in System32
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return sys32;
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (systemDirectory.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::wstring fullCommandline{
|
||||||
|
wil::ExpandEnvironmentStringsW<std::wstring>(commandLine.data())
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fullCommandline.size() > systemDirectory.size())
|
||||||
|
{
|
||||||
|
// Get the first part of the executable path
|
||||||
|
const auto start = fullCommandline.substr(0, systemDirectory.size());
|
||||||
|
// Doing this as an ASCII only check might be wrong, but I'm
|
||||||
|
// guessing if system32 isn't at X:\windows\system32... this isn't
|
||||||
|
// the only thing that is going to be sad in Windows.
|
||||||
|
const auto pathEquals = til::equals_insensitive_ascii(start, systemDirectory);
|
||||||
|
if (pathEquals && std::filesystem::exists(std::filesystem::path{ fullCommandline }))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're explicitly not auto-allowing wsl.exe -d <distro name>. It's
|
||||||
|
// trivial to insert some malicious stuff into WSL, via .bash_profile,
|
||||||
|
// so we're not giving them the (y)
|
||||||
|
|
||||||
|
// But we do want to allow `pwsh.exe` profiles in the expected place to
|
||||||
|
// work.
|
||||||
|
const std::vector<std::filesystem::path> powershellCoreRoots
|
||||||
|
{
|
||||||
|
// Always look in "%LOCALAPPDATA%\Microsoft\WindowsApps", which is
|
||||||
|
// where the pwsh.exe execution alias lives.
|
||||||
|
{ wil::ExpandEnvironmentStringsW<std::wstring>(L"%LOCALAPPDATA%\\Microsoft\\WindowsApps") },
|
||||||
|
|
||||||
|
// Always look in "%ProgramFiles%\PowerShell"
|
||||||
|
{ wil::ExpandEnvironmentStringsW<std::wstring>(L"%ProgramFiles%\\PowerShell") },
|
||||||
|
|
||||||
|
#if defined(_M_AMD64) || defined(_M_ARM64) // No point in looking for WOW if we're not somewhere it exists
|
||||||
|
{ wil::ExpandEnvironmentStringsW<std::wstring>(L"%ProgramFiles(x86)%\\PowerShell") },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_M_ARM64) // same with ARM
|
||||||
|
{
|
||||||
|
wil::ExpandEnvironmentStringsW<std::wstring>(L"%ProgramFiles(Arm)%\\PowerShell")
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Is the filename for this commandline `pwsh.exe`?
|
||||||
|
const std::filesystem::path exePath{ fullCommandline };
|
||||||
|
const auto endsWithPwsh{ exePath.filename() == L"pwsh.exe" };
|
||||||
|
// We'll also need to check the parent path, so make sure it has one here.
|
||||||
|
|
||||||
|
if (endsWithPwsh && exePath.has_parent_path())
|
||||||
|
{
|
||||||
|
const auto parentPath{ exePath.parent_path() };
|
||||||
|
for (const auto& pwshRoot : powershellCoreRoots)
|
||||||
|
{
|
||||||
|
// Does the commandline start with this root, and end with pwsh.exe?
|
||||||
|
const auto startsWithRoot{ til::starts_with(fullCommandline, pwshRoot.c_str()) };
|
||||||
|
|
||||||
|
// Is either the immediate parent, or the grandparent, this root exactly?
|
||||||
|
//
|
||||||
|
// We need to check the grandparent for the
|
||||||
|
// `%ProgramFiles%\\PowerShell\\7\\pwsh.exe` case.
|
||||||
|
const auto parentIsCorrect = (parentPath == pwshRoot) ||
|
||||||
|
(parentPath.has_parent_path() && parentPath.parent_path() == pwshRoot);
|
||||||
|
|
||||||
|
if (startsWithRoot && parentIsCorrect)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - For a given commandline, determines if we should prompt the user for
|
||||||
|
// approval. We only do this check when elevated. This will check the
|
||||||
|
// AllowedCommandlines in `elevated-state.json`, to see if the commandline
|
||||||
|
// already exists in that list.
|
||||||
|
// Arguments:
|
||||||
|
// - cmdline: The commandline to check
|
||||||
|
// Return Value:
|
||||||
|
// - true if we should prompt the user for approval.
|
||||||
|
bool TerminalPage::_shouldPromptForCommandline(const winrt::hstring& cmdline) const
|
||||||
|
{
|
||||||
|
// NOTE: For debugging purposes, changing this to `true || IsElevated()`
|
||||||
|
// is a handy way of forcing the elevation logic, even when unelevated.
|
||||||
|
if (IsElevated())
|
||||||
|
{
|
||||||
|
// If the cmdline is EXACTLY an executable in
|
||||||
|
// `C:\WINDOWS\System32`, then ignore this check.
|
||||||
|
if (_isTrustedCommandline(cmdline))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto& allowedCommandlines{ ApplicationState::SharedInstance().AllowedCommandlines() })
|
||||||
|
{
|
||||||
|
for (const auto& approved : allowedCommandlines)
|
||||||
|
{
|
||||||
|
if (approved == cmdline)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalPage::_adminWarningPrimaryClicked(const TerminalApp::AdminWarningPlaceholder& sender,
|
||||||
|
const winrt::Windows::UI::Xaml::RoutedEventArgs& /*args*/)
|
||||||
|
{
|
||||||
|
auto warningControl{ winrt::get_self<AdminWarningPlaceholder>(sender) };
|
||||||
|
const auto& cmdline{ warningControl->Commandline() };
|
||||||
|
// Look through the tabs and panes to look for us. Whichever pane had us
|
||||||
|
// as content - replace their content with the TermControl we were
|
||||||
|
// holding on to.
|
||||||
|
for (const auto& tab : _tabs)
|
||||||
|
{
|
||||||
|
if (const auto& tabImpl{ _GetTerminalTabImpl(tab) })
|
||||||
|
{
|
||||||
|
tabImpl->GetRootPane()->WalkTree([warningControl, cmdline, tabImpl](std::shared_ptr<Pane> pane) -> bool {
|
||||||
|
const auto& projectedWarningControl{ pane->GetUserControl().try_as<TerminalApp::AdminWarningPlaceholder>() };
|
||||||
|
// If it was a warning control, then get our implementation
|
||||||
|
// type out of it.
|
||||||
|
if (const auto& otherWarning{ winrt::get_self<AdminWarningPlaceholder>(projectedWarningControl) })
|
||||||
|
{
|
||||||
|
// This pane had a warning in it.
|
||||||
|
// Was it a warning for the same commandline that we
|
||||||
|
// just approved?
|
||||||
|
if (otherWarning->Commandline() == cmdline)
|
||||||
|
{
|
||||||
|
// Go ahead and allow them. Swap the control into
|
||||||
|
// the pane, which will initialize and start it.
|
||||||
|
tabImpl->ReplaceControl(pane, otherWarning->Control());
|
||||||
|
}
|
||||||
|
// Don't return true here. We want to make sure to check
|
||||||
|
// all the panes for the same commandline we just
|
||||||
|
// approved.
|
||||||
|
}
|
||||||
|
// return false so we make sure to iterate on every leaf.
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the list of approved commandlines.
|
||||||
|
auto allowedCommandlines{ ApplicationState::SharedInstance().AllowedCommandlines() };
|
||||||
|
if (!allowedCommandlines)
|
||||||
|
{
|
||||||
|
allowedCommandlines = winrt::single_threaded_vector<winrt::hstring>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// But of course, we don't need to add this commandline if it's already
|
||||||
|
// in the list of approved commandlines.
|
||||||
|
bool foundCopy = false;
|
||||||
|
for (const auto& approved : allowedCommandlines)
|
||||||
|
{
|
||||||
|
if (approved == cmdline)
|
||||||
|
{
|
||||||
|
foundCopy = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundCopy)
|
||||||
|
{
|
||||||
|
allowedCommandlines.Append(cmdline);
|
||||||
|
}
|
||||||
|
ApplicationState::SharedInstance().AllowedCommandlines(allowedCommandlines);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerminalPage::_adminWarningCancelClicked(const TerminalApp::AdminWarningPlaceholder& sender,
|
||||||
|
const winrt::Windows::UI::Xaml::RoutedEventArgs& /*args*/)
|
||||||
|
{
|
||||||
|
auto warningControl{ winrt::get_self<AdminWarningPlaceholder>(sender) };
|
||||||
|
|
||||||
|
for (const auto& tab : _tabs)
|
||||||
|
{
|
||||||
|
if (const auto& tabImpl{ _GetTerminalTabImpl(tab) })
|
||||||
|
{
|
||||||
|
tabImpl->GetRootPane()->WalkTree([warningControl](std::shared_ptr<Pane> pane) -> bool {
|
||||||
|
if (pane->GetUserControl() == *warningControl)
|
||||||
|
{
|
||||||
|
pane->Close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// We're not going to auto-close all the other panes with
|
||||||
|
// the same commandline warning, akin to what we're doing in
|
||||||
|
// the approve handler. If they want to reject one pane, but
|
||||||
|
// accept the next one, that's okay.
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Split the focused pane either horizontally or vertically, and place the
|
// - Split the focused pane either horizontally or vertically, and place the
|
||||||
// given pane accordingly in the tree
|
// given pane accordingly in the tree
|
||||||
|
@ -1852,8 +2096,10 @@ namespace winrt::TerminalApp::implementation
|
||||||
if (warnMultiLine)
|
if (warnMultiLine)
|
||||||
{
|
{
|
||||||
const auto focusedTab = _GetFocusedTabImpl();
|
const auto focusedTab = _GetFocusedTabImpl();
|
||||||
|
const auto& termControl{ focusedTab->GetActiveTerminalControl() };
|
||||||
// Do not warn about multi line pasting if the current tab has bracketed paste enabled.
|
// Do not warn about multi line pasting if the current tab has bracketed paste enabled.
|
||||||
warnMultiLine = warnMultiLine && !focusedTab->GetActiveTerminalControl().BracketedPasteEnabled();
|
warnMultiLine = warnMultiLine &&
|
||||||
|
(termControl && !termControl.BracketedPasteEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to initialize the dialog here to be able to change the text of the text block within it
|
// We have to initialize the dialog here to be able to change the text of the text block within it
|
||||||
|
@ -2123,13 +2369,10 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
TermControl TerminalPage::_InitControl(const TerminalSettingsCreateResult& settings, const ITerminalConnection& connection)
|
TermControl TerminalPage::_InitControl(const TerminalSettingsCreateResult& settings, const ITerminalConnection& connection)
|
||||||
{
|
{
|
||||||
// Give term control a child of the settings so that any overrides go in the child
|
// Do any initialization that needs to apply to _every_ TermControl we
|
||||||
// This way, when we do a settings reload we just update the parent and the overrides remain
|
// create here.
|
||||||
const auto child = TerminalSettings::CreateWithParent(settings);
|
// TermControl will copy the settings out of the settings passed to it.
|
||||||
TermControl term{ child.DefaultSettings(), connection };
|
TermControl term{ settings.DefaultSettings(), settings.UnfocusedSettings(), connection };
|
||||||
|
|
||||||
term.UnfocusedAppearance(child.UnfocusedSettings()); // It is okay for the unfocused settings to be null
|
|
||||||
|
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2161,7 +2404,9 @@ namespace winrt::TerminalApp::implementation
|
||||||
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
|
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
|
||||||
profile = GetClosestProfileForDuplicationOfProfile(profile);
|
profile = GetClosestProfileForDuplicationOfProfile(profile);
|
||||||
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
|
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
|
||||||
const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory();
|
if (const auto& control{ focusedTab->GetActiveTerminalControl() })
|
||||||
|
{
|
||||||
|
const auto workingDirectory = control.WorkingDirectory();
|
||||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||||
if (validWorkingDirectory)
|
if (validWorkingDirectory)
|
||||||
{
|
{
|
||||||
|
@ -2170,6 +2415,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!profile)
|
if (!profile)
|
||||||
{
|
{
|
||||||
profile = _settings.GetProfileForArgs(newTerminalArgs);
|
profile = _settings.GetProfileForArgs(newTerminalArgs);
|
||||||
|
@ -2199,7 +2445,21 @@ namespace winrt::TerminalApp::implementation
|
||||||
const auto control = _InitControl(controlSettings, connection);
|
const auto control = _InitControl(controlSettings, connection);
|
||||||
_RegisterTerminalEvents(control);
|
_RegisterTerminalEvents(control);
|
||||||
|
|
||||||
auto resultPane = std::make_shared<Pane>(profile, control);
|
WUX::Controls::UserControl controlToAdd{ control };
|
||||||
|
|
||||||
|
// Check if we should warn the user about running a new unelevated
|
||||||
|
// commandline.
|
||||||
|
const auto& cmdline{ controlSettings.DefaultSettings().Commandline() };
|
||||||
|
const auto doAdminWarning{ _shouldPromptForCommandline(cmdline) };
|
||||||
|
if (doAdminWarning)
|
||||||
|
{
|
||||||
|
auto warningControl{ winrt::make_self<implementation::AdminWarningPlaceholder>(control, cmdline) };
|
||||||
|
warningControl->PrimaryButtonClicked({ get_weak(), &TerminalPage::_adminWarningPrimaryClicked });
|
||||||
|
warningControl->CancelButtonClicked({ get_weak(), &TerminalPage::_adminWarningCancelClicked });
|
||||||
|
controlToAdd = *warningControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto resultPane = std::make_shared<Pane>(profile, controlToAdd);
|
||||||
|
|
||||||
if (debugConnection) // this will only be set if global debugging is on and tap is active
|
if (debugConnection) // this will only be set if global debugging is on and tap is active
|
||||||
{
|
{
|
||||||
|
@ -2220,6 +2480,17 @@ namespace winrt::TerminalApp::implementation
|
||||||
original->SetActive();
|
original->SetActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doAdminWarning)
|
||||||
|
{
|
||||||
|
// We know this is safe - we literally just added the
|
||||||
|
// AdminWarningPlaceholder as the controlToAdd like 20 lines up.
|
||||||
|
//
|
||||||
|
// Focus the warning here. The LayoutUpdated within the dialog
|
||||||
|
// itself isn't good enough. That, for some reason, fires _before_
|
||||||
|
// the dialog is in the UI tree, which is useless for us.
|
||||||
|
controlToAdd.try_as<implementation::AdminWarningPlaceholder>()->FocusOnLaunch();
|
||||||
|
}
|
||||||
|
|
||||||
return resultPane;
|
return resultPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace TerminalAppLocalTests
|
||||||
{
|
{
|
||||||
class TabTests;
|
class TabTests;
|
||||||
class SettingsTests;
|
class SettingsTests;
|
||||||
|
class TrustCommandlineTests;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace winrt::TerminalApp::implementation
|
namespace winrt::TerminalApp::implementation
|
||||||
|
@ -207,6 +208,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCloseReadOnlyDialog();
|
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCloseReadOnlyDialog();
|
||||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowMultiLinePasteWarningDialog();
|
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowMultiLinePasteWarningDialog();
|
||||||
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowLargePasteWarningDialog();
|
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowLargePasteWarningDialog();
|
||||||
|
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCommandlineApproveWarning();
|
||||||
|
|
||||||
void _CreateNewTabFlyout();
|
void _CreateNewTabFlyout();
|
||||||
void _OpenNewTabDropdown();
|
void _OpenNewTabDropdown();
|
||||||
|
@ -403,6 +405,12 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetClosestProfileForDuplicationOfProfile(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile) const noexcept;
|
winrt::Microsoft::Terminal::Settings::Model::Profile GetClosestProfileForDuplicationOfProfile(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile) const noexcept;
|
||||||
|
|
||||||
|
bool _shouldPromptForCommandline(const winrt::hstring& cmdline) const;
|
||||||
|
void _adminWarningPrimaryClicked(const winrt::TerminalApp::AdminWarningPlaceholder& sender,
|
||||||
|
const winrt::Windows::UI::Xaml::RoutedEventArgs& args);
|
||||||
|
void _adminWarningCancelClicked(const winrt::TerminalApp::AdminWarningPlaceholder& sender,
|
||||||
|
const winrt::Windows::UI::Xaml::RoutedEventArgs& args);
|
||||||
|
|
||||||
winrt::fire_and_forget _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
winrt::fire_and_forget _ConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||||
void _CloseOnExitInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
void _CloseOnExitInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||||
void _KeyboardServiceWarningInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
void _KeyboardServiceWarningInfoDismissHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args) const;
|
||||||
|
@ -410,6 +418,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
void _SetAsDefaultOpenSettingsHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
void _SetAsDefaultOpenSettingsHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
|
||||||
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
|
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
|
||||||
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
|
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
|
||||||
|
static bool _isTrustedCommandline(std::wstring_view commandLine);
|
||||||
|
|
||||||
#pragma region ActionHandlers
|
#pragma region ActionHandlers
|
||||||
// These are all defined in AppActionHandlers.cpp
|
// These are all defined in AppActionHandlers.cpp
|
||||||
|
@ -420,6 +429,7 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
friend class TerminalAppLocalTests::TabTests;
|
friend class TerminalAppLocalTests::TabTests;
|
||||||
friend class TerminalAppLocalTests::SettingsTests;
|
friend class TerminalAppLocalTests::SettingsTests;
|
||||||
|
friend class TerminalAppLocalTests::TrustCommandlineTests;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,10 @@ namespace winrt::TerminalApp::implementation
|
||||||
winrt::fire_and_forget TerminalTab::Scroll(const int delta)
|
winrt::fire_and_forget TerminalTab::Scroll(const int delta)
|
||||||
{
|
{
|
||||||
auto control = GetActiveTerminalControl();
|
auto control = GetActiveTerminalControl();
|
||||||
|
if (!control)
|
||||||
|
{
|
||||||
|
co_return;
|
||||||
|
}
|
||||||
co_await winrt::resume_foreground(control.Dispatcher());
|
co_await winrt::resume_foreground(control.Dispatcher());
|
||||||
|
|
||||||
const auto currentOffset = control.ScrollOffset();
|
const auto currentOffset = control.ScrollOffset();
|
||||||
|
@ -511,7 +514,11 @@ namespace winrt::TerminalApp::implementation
|
||||||
if (p->_IsLeaf())
|
if (p->_IsLeaf())
|
||||||
{
|
{
|
||||||
p->Id(_nextPaneId);
|
p->Id(_nextPaneId);
|
||||||
_AttachEventHandlersToControl(p->Id().value(), p->_control);
|
if (auto termControl{ p->_control.try_as<TermControl>() })
|
||||||
|
{
|
||||||
|
_AttachEventHandlersToControl(p->Id().value(), termControl);
|
||||||
|
}
|
||||||
|
|
||||||
_nextPaneId++;
|
_nextPaneId++;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -856,6 +863,10 @@ namespace winrt::TerminalApp::implementation
|
||||||
// - <none>
|
// - <none>
|
||||||
void TerminalTab::_AttachEventHandlersToControl(const uint32_t paneId, const TermControl& control)
|
void TerminalTab::_AttachEventHandlersToControl(const uint32_t paneId, const TermControl& control)
|
||||||
{
|
{
|
||||||
|
if (!control)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto weakThis{ get_weak() };
|
auto weakThis{ get_weak() };
|
||||||
auto dispatcher = TabViewItem().Dispatcher();
|
auto dispatcher = TabViewItem().Dispatcher();
|
||||||
ControlEventTokens events{};
|
ControlEventTokens events{};
|
||||||
|
@ -1744,6 +1755,19 @@ namespace winrt::TerminalApp::implementation
|
||||||
return Title();
|
return Title();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalTab::ReplaceControl(std::shared_ptr<Pane> pane, const Controls::UserControl& control)
|
||||||
|
{
|
||||||
|
pane->ReplaceControl(control);
|
||||||
|
|
||||||
|
if (auto termControl{ pane->_control.try_as<TermControl>() })
|
||||||
|
{
|
||||||
|
_AttachEventHandlersToControl(pane->Id().value(), termControl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the title manually.
|
||||||
|
UpdateTitle();
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_EVENT(TerminalTab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
|
DEFINE_EVENT(TerminalTab, ActivePaneChanged, _ActivePaneChangedHandlers, winrt::delegate<>);
|
||||||
DEFINE_EVENT(TerminalTab, ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
|
DEFINE_EVENT(TerminalTab, ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
|
||||||
DEFINE_EVENT(TerminalTab, ColorCleared, _colorCleared, winrt::delegate<>);
|
DEFINE_EVENT(TerminalTab, ColorCleared, _colorCleared, winrt::delegate<>);
|
||||||
|
|
|
@ -93,6 +93,9 @@ namespace winrt::TerminalApp::implementation
|
||||||
|
|
||||||
std::shared_ptr<Pane> GetRootPane() const { return _rootPane; }
|
std::shared_ptr<Pane> GetRootPane() const { return _rootPane; }
|
||||||
|
|
||||||
|
void ReplaceControl(std::shared_ptr<Pane> pane,
|
||||||
|
const winrt::Windows::UI::Xaml::Controls::UserControl& control);
|
||||||
|
|
||||||
winrt::TerminalApp::TerminalTabStatus TabStatus()
|
winrt::TerminalApp::TerminalTabStatus TabStatus()
|
||||||
{
|
{
|
||||||
return _tabStatus;
|
return _tabStatus;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
//
|
//
|
||||||
// TitlebarControl.xaml.cpp
|
|
||||||
// Implementation of the TitlebarControl class
|
// Implementation of the TitlebarControl class
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -24,6 +23,14 @@ namespace winrt::TerminalApp::implementation
|
||||||
MinMaxCloseControl().CloseClick({ this, &TitlebarControl::Close_Click });
|
MinMaxCloseControl().CloseClick({ this, &TitlebarControl::Close_Click });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double TitlebarControl::CaptionButtonWidth()
|
||||||
|
{
|
||||||
|
// Divide by three, since we know there are only three buttons. When
|
||||||
|
// Windows 12 comes along and adds another, we can update this /s
|
||||||
|
static double width{ MinMaxCloseControl().ActualWidth() / 3.0 };
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
IInspectable TitlebarControl::Content()
|
IInspectable TitlebarControl::Content()
|
||||||
{
|
{
|
||||||
return ContentRoot().Content();
|
return ContentRoot().Content();
|
||||||
|
@ -93,4 +100,48 @@ namespace winrt::TerminalApp::implementation
|
||||||
{
|
{
|
||||||
MinMaxCloseControl().SetWindowVisualState(visualState);
|
MinMaxCloseControl().SetWindowVisualState(visualState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GH#9443: HoverButton, PressButton, ClickButton and ReleaseButtons are all
|
||||||
|
// used to manually interact with the buttons, in the same way that XAML
|
||||||
|
// would normally send events.
|
||||||
|
|
||||||
|
void TitlebarControl::HoverButton(CaptionButton button)
|
||||||
|
{
|
||||||
|
MinMaxCloseControl().HoverButton(button);
|
||||||
|
}
|
||||||
|
void TitlebarControl::PressButton(CaptionButton button)
|
||||||
|
{
|
||||||
|
MinMaxCloseControl().PressButton(button);
|
||||||
|
}
|
||||||
|
winrt::fire_and_forget TitlebarControl::ClickButton(CaptionButton button)
|
||||||
|
{
|
||||||
|
// GH#8587: Handle this on the _next_ pass of the UI thread. If we
|
||||||
|
// handle this immediately, then we'll accidentally leave the button in
|
||||||
|
// the "Hovered" state when we minimize. This will leave the button
|
||||||
|
// visibly hovered in the taskbar preview for our window.
|
||||||
|
auto weakThis{ get_weak() };
|
||||||
|
co_await MinMaxCloseControl().Dispatcher();
|
||||||
|
if (auto self{ weakThis.get() })
|
||||||
|
{
|
||||||
|
// Just handle this in the same way we would if the button were
|
||||||
|
// clicked normally.
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case CaptionButton::Minimize:
|
||||||
|
Minimize_Click(nullptr, nullptr);
|
||||||
|
break;
|
||||||
|
case CaptionButton::Maximize:
|
||||||
|
Maximize_Click(nullptr, nullptr);
|
||||||
|
break;
|
||||||
|
case CaptionButton::Close:
|
||||||
|
Close_Click(nullptr, nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TitlebarControl::ReleaseButtons()
|
||||||
|
{
|
||||||
|
MinMaxCloseControl().ReleaseButtons();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
// Copyright (c) Microsoft Corporation.
|
// Copyright (c) Microsoft Corporation.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
//
|
|
||||||
// Declaration of the MainUserControl class.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "winrt/Windows.UI.Xaml.h"
|
|
||||||
#include "winrt/Windows.UI.Xaml.Markup.h"
|
|
||||||
#include "winrt/Windows.UI.Xaml.Interop.h"
|
|
||||||
#include "TitlebarControl.g.h"
|
#include "TitlebarControl.g.h"
|
||||||
|
|
||||||
namespace winrt::TerminalApp::implementation
|
namespace winrt::TerminalApp::implementation
|
||||||
|
@ -17,6 +11,12 @@ namespace winrt::TerminalApp::implementation
|
||||||
{
|
{
|
||||||
TitlebarControl(uint64_t handle);
|
TitlebarControl(uint64_t handle);
|
||||||
|
|
||||||
|
void HoverButton(CaptionButton button);
|
||||||
|
void PressButton(CaptionButton button);
|
||||||
|
winrt::fire_and_forget ClickButton(CaptionButton button);
|
||||||
|
void ReleaseButtons();
|
||||||
|
double CaptionButtonWidth();
|
||||||
|
|
||||||
IInspectable Content();
|
IInspectable Content();
|
||||||
void Content(IInspectable content);
|
void Content(IInspectable content);
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,25 @@ namespace TerminalApp
|
||||||
WindowVisualStateIconified
|
WindowVisualStateIconified
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// For simplicity, make sure that these are the same values as the ones used
|
||||||
|
// by messages like WM_NCHITTEST
|
||||||
|
enum CaptionButton {
|
||||||
|
Minimize = 8, // HTMINBUTTON
|
||||||
|
Maximize = 9, // HTMAXBUTTON
|
||||||
|
Close = 20 // HTCLOSE
|
||||||
|
};
|
||||||
|
|
||||||
[default_interface] runtimeclass TitlebarControl : Windows.UI.Xaml.Controls.Grid
|
[default_interface] runtimeclass TitlebarControl : Windows.UI.Xaml.Controls.Grid
|
||||||
{
|
{
|
||||||
TitlebarControl(UInt64 parentWindowHandle);
|
TitlebarControl(UInt64 parentWindowHandle);
|
||||||
void SetWindowVisualState(WindowVisualState visualState);
|
void SetWindowVisualState(WindowVisualState visualState);
|
||||||
|
|
||||||
|
void HoverButton(CaptionButton button);
|
||||||
|
void PressButton(CaptionButton button);
|
||||||
|
void ClickButton(CaptionButton button);
|
||||||
|
void ReleaseButtons();
|
||||||
|
Double CaptionButtonWidth { get; };
|
||||||
|
|
||||||
IInspectable Content;
|
IInspectable Content;
|
||||||
Windows.UI.Xaml.Controls.Border DragBar { get; };
|
Windows.UI.Xaml.Controls.Border DragBar { get; };
|
||||||
}
|
}
|
||||||
|
|
49
src/cascadia/TerminalControl/ControlAppearance.h
Normal file
49
src/cascadia/TerminalControl/ControlAppearance.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) Microsoft Corporation
|
||||||
|
Licensed under the MIT license.
|
||||||
|
--*/
|
||||||
|
#pragma once
|
||||||
|
#include "../../inc/cppwinrt_utils.h"
|
||||||
|
#include "../../inc/ControlProperties.h"
|
||||||
|
|
||||||
|
#include <DefaultSettings.h>
|
||||||
|
#include <conattrs.hpp>
|
||||||
|
|
||||||
|
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
{
|
||||||
|
struct ControlAppearance : public winrt::implements<ControlAppearance, Microsoft::Terminal::Core::ICoreAppearance, Microsoft::Terminal::Control::IControlAppearance>
|
||||||
|
{
|
||||||
|
#define SETTINGS_GEN(type, name, ...) WINRT_PROPERTY(type, name, __VA_ARGS__);
|
||||||
|
CORE_APPEARANCE_SETTINGS(SETTINGS_GEN)
|
||||||
|
CONTROL_APPEARANCE_SETTINGS(SETTINGS_GEN)
|
||||||
|
#undef SETTINGS_GEN
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Color Table is special because it's an array
|
||||||
|
std::array<winrt::Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE> _ColorTable;
|
||||||
|
|
||||||
|
public:
|
||||||
|
winrt::Microsoft::Terminal::Core::Color GetColorTableEntry(int32_t index) noexcept
|
||||||
|
{
|
||||||
|
return _ColorTable.at(index);
|
||||||
|
}
|
||||||
|
void SetColorTableEntry(int32_t index,
|
||||||
|
winrt::Microsoft::Terminal::Core::Color color) noexcept
|
||||||
|
{
|
||||||
|
_ColorTable.at(index) = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlAppearance(Control::IControlAppearance appearance)
|
||||||
|
{
|
||||||
|
#define COPY_SETTING(type, name, ...) _##name = appearance.name();
|
||||||
|
CORE_APPEARANCE_SETTINGS(COPY_SETTING)
|
||||||
|
CONTROL_APPEARANCE_SETTINGS(COPY_SETTING)
|
||||||
|
#undef COPY_SETTING
|
||||||
|
|
||||||
|
for (size_t i = 0; i < _ColorTable.size(); i++)
|
||||||
|
{
|
||||||
|
_ColorTable[i] = appearance.GetColorTableEntry(static_cast<int32_t>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -56,15 +56,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
return initialized;
|
return initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlCore::ControlCore(IControlSettings settings,
|
ControlCore::ControlCore(Control::IControlSettings settings,
|
||||||
|
Control::IControlAppearance unfocusedAppearance,
|
||||||
TerminalConnection::ITerminalConnection connection) :
|
TerminalConnection::ITerminalConnection connection) :
|
||||||
_connection{ connection },
|
_connection{ connection },
|
||||||
_settings{ settings },
|
|
||||||
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8 },
|
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8 },
|
||||||
_actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false }
|
_actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false }
|
||||||
{
|
{
|
||||||
_EnsureStaticInitialization();
|
_EnsureStaticInitialization();
|
||||||
|
|
||||||
|
_settings = winrt::make_self<implementation::ControlSettings>(settings, unfocusedAppearance);
|
||||||
|
|
||||||
_terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>();
|
_terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>();
|
||||||
|
|
||||||
// Subscribe to the connection's disconnected event and call our connection closed handlers.
|
// Subscribe to the connection's disconnected event and call our connection closed handlers.
|
||||||
|
@ -80,7 +82,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
});
|
});
|
||||||
|
|
||||||
// GH#8969: pre-seed working directory to prevent potential races
|
// GH#8969: pre-seed working directory to prevent potential races
|
||||||
_terminal->SetWorkingDirectory(_settings.StartingDirectory());
|
_terminal->SetWorkingDirectory(_settings->StartingDirectory());
|
||||||
|
|
||||||
auto pfnCopyToClipboard = std::bind(&ControlCore::_terminalCopyToClipboard, this, std::placeholders::_1);
|
auto pfnCopyToClipboard = std::bind(&ControlCore::_terminalCopyToClipboard, this, std::placeholders::_1);
|
||||||
_terminal->SetCopyToClipboardCallback(pfnCopyToClipboard);
|
_terminal->SetCopyToClipboardCallback(pfnCopyToClipboard);
|
||||||
|
@ -187,7 +189,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
UpdateSettings(settings);
|
UpdateSettings(settings, unfocusedAppearance);
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlCore::~ControlCore()
|
ControlCore::~ControlCore()
|
||||||
|
@ -226,7 +228,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Feature_AtlasEngine::IsEnabled() && _settings.UseAtlasEngine())
|
if (Feature_AtlasEngine::IsEnabled() && _settings->UseAtlasEngine())
|
||||||
{
|
{
|
||||||
_renderEngine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
|
_renderEngine = std::make_unique<::Microsoft::Console::Render::AtlasEngine>();
|
||||||
}
|
}
|
||||||
|
@ -252,7 +254,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
LOG_IF_FAILED(_renderEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
|
LOG_IF_FAILED(_renderEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
|
||||||
|
|
||||||
// Update DxEngine's SelectionBackground
|
// Update DxEngine's SelectionBackground
|
||||||
_renderEngine->SetSelectionBackground(til::color{ _settings.SelectionBackground() });
|
_renderEngine->SetSelectionBackground(til::color{ _settings->SelectionBackground() });
|
||||||
|
|
||||||
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
|
||||||
const auto width = vp.Width();
|
const auto width = vp.Width();
|
||||||
|
@ -260,10 +262,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
_connection.Resize(height, width);
|
_connection.Resize(height, width);
|
||||||
|
|
||||||
// Override the default width and height to match the size of the swapChainPanel
|
// Override the default width and height to match the size of the swapChainPanel
|
||||||
_settings.InitialCols(width);
|
_settings->InitialCols(width);
|
||||||
_settings.InitialRows(height);
|
_settings->InitialRows(height);
|
||||||
|
|
||||||
_terminal->CreateFromSettings(_settings, *_renderer);
|
_terminal->CreateFromSettings(*_settings, *_renderer);
|
||||||
|
|
||||||
// IMPORTANT! Set this callback up sooner than later. If we do it
|
// IMPORTANT! Set this callback up sooner than later. If we do it
|
||||||
// after Enable, then it'll be possible to paint the frame once
|
// after Enable, then it'll be possible to paint the frame once
|
||||||
|
@ -275,18 +277,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// We do this after we initially set the swapchain so as to avoid unnecessary callbacks (and locking problems)
|
// We do this after we initially set the swapchain so as to avoid unnecessary callbacks (and locking problems)
|
||||||
_renderEngine->SetCallback(std::bind(&ControlCore::_renderEngineSwapChainChanged, this));
|
_renderEngine->SetCallback(std::bind(&ControlCore::_renderEngineSwapChainChanged, this));
|
||||||
|
|
||||||
_renderEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect());
|
_renderEngine->SetRetroTerminalEffect(_settings->RetroTerminalEffect());
|
||||||
_renderEngine->SetPixelShaderPath(_settings.PixelShaderPath());
|
_renderEngine->SetPixelShaderPath(_settings->PixelShaderPath());
|
||||||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
_renderEngine->SetForceFullRepaintRendering(_settings->ForceFullRepaintRendering());
|
||||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
_renderEngine->SetSoftwareRendering(_settings->SoftwareRendering());
|
||||||
_renderEngine->SetIntenseIsBold(_settings.IntenseIsBold());
|
_renderEngine->SetIntenseIsBold(_settings->IntenseIsBold());
|
||||||
|
|
||||||
_updateAntiAliasingMode();
|
_updateAntiAliasingMode();
|
||||||
|
|
||||||
// GH#5098: Inform the engine of the opacity of the default text background.
|
// GH#5098: Inform the engine of the opacity of the default text background.
|
||||||
// GH#11315: Always do this, even if they don't have acrylic on.
|
// GH#11315: Always do this, even if they don't have acrylic on.
|
||||||
const auto backgroundIsOpaque = _settings.Opacity() == 1.0 && _settings.BackgroundImage().empty();
|
_renderEngine->EnableTransparentBackground(_isBackgroundTransparent());
|
||||||
_renderEngine->SetDefaultTextBackgroundOpacity(static_cast<float>(backgroundIsOpaque));
|
|
||||||
|
|
||||||
THROW_IF_FAILED(_renderEngine->Enable());
|
THROW_IF_FAILED(_renderEngine->Enable());
|
||||||
|
|
||||||
|
@ -444,14 +445,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newOpacity = std::clamp(_settings.Opacity() + adjustment,
|
auto newOpacity = std::clamp(Opacity() + adjustment,
|
||||||
0.0,
|
0.0,
|
||||||
1.0);
|
1.0);
|
||||||
|
|
||||||
// GH#5098: Inform the engine of the new opacity of the default text background.
|
auto lock = _terminal->LockForWriting();
|
||||||
SetBackgroundOpacity(::base::saturated_cast<float>(newOpacity));
|
// Update our runtime opacity value
|
||||||
|
Opacity(newOpacity);
|
||||||
_settings.Opacity(newOpacity);
|
|
||||||
|
|
||||||
// GH#11285 - If the user is on Windows 10, and they changed the
|
// GH#11285 - If the user is on Windows 10, and they changed the
|
||||||
// transparency of the control s.t. it should be partially opaque, then
|
// transparency of the control s.t. it should be partially opaque, then
|
||||||
|
@ -461,7 +461,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// is what the Terminal did prior to 1.12.
|
// is what the Terminal did prior to 1.12.
|
||||||
if (!IsVintageOpacityAvailable())
|
if (!IsVintageOpacityAvailable())
|
||||||
{
|
{
|
||||||
_settings.UseAcrylic(newOpacity < 1.0);
|
_runtimeUseAcrylic = newOpacity < 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the renderer as well. It might need to fall back from
|
||||||
|
// cleartype -> grayscale if the BG is transparent / acrylic.
|
||||||
|
if (_renderEngine)
|
||||||
|
{
|
||||||
|
_renderEngine->EnableTransparentBackground(_isBackgroundTransparent());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(newOpacity);
|
auto eventArgs = winrt::make_self<TransparencyChangedEventArgs>(newOpacity);
|
||||||
|
@ -476,7 +483,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// specify a custom pixel shader, manually enable the legacy retro
|
// specify a custom pixel shader, manually enable the legacy retro
|
||||||
// effect first. This will ensure that a toggle off->on will still work,
|
// effect first. This will ensure that a toggle off->on will still work,
|
||||||
// even if they currently have retro effect off.
|
// even if they currently have retro effect off.
|
||||||
if (_settings.PixelShaderPath().empty() && !_renderEngine->GetRetroTerminalEffect())
|
if (_settings->PixelShaderPath().empty() && !_renderEngine->GetRetroTerminalEffect())
|
||||||
{
|
{
|
||||||
// SetRetroTerminalEffect to true will enable the effect. In this
|
// SetRetroTerminalEffect to true will enable the effect. In this
|
||||||
// case, the shader effect will already be disabled (because neither
|
// case, the shader effect will already be disabled (because neither
|
||||||
|
@ -586,24 +593,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Updates the settings of the current terminal.
|
// - Updates the settings of the current terminal.
|
||||||
// - INVARIANT: This method can only be called if the caller DOES NOT HAVE writing lock on the terminal.
|
// - INVARIANT: This method can only be called if the caller DOES NOT HAVE writing lock on the terminal.
|
||||||
void ControlCore::UpdateSettings(const IControlSettings& settings)
|
void ControlCore::UpdateSettings(const IControlSettings& settings, const IControlAppearance& newAppearance)
|
||||||
{
|
{
|
||||||
|
_settings = winrt::make_self<implementation::ControlSettings>(settings, newAppearance);
|
||||||
|
|
||||||
auto lock = _terminal->LockForWriting();
|
auto lock = _terminal->LockForWriting();
|
||||||
|
|
||||||
_settings = settings;
|
_runtimeOpacity = std::nullopt;
|
||||||
|
_runtimeUseAcrylic = std::nullopt;
|
||||||
|
|
||||||
// GH#11285 - If the user is on Windows 10, and they wanted opacity, but
|
// GH#11285 - If the user is on Windows 10, and they wanted opacity, but
|
||||||
// didn't explicitly request acrylic, then opt them in to acrylic.
|
// didn't explicitly request acrylic, then opt them in to acrylic.
|
||||||
// On Windows 11+, this isn't needed, because we can have vintage opacity.
|
// On Windows 11+, this isn't needed, because we can have vintage opacity.
|
||||||
if (!IsVintageOpacityAvailable() && _settings.Opacity() < 1.0 && !_settings.UseAcrylic())
|
if (!IsVintageOpacityAvailable() && _settings->Opacity() < 1.0 && !_settings->UseAcrylic())
|
||||||
{
|
{
|
||||||
_settings.UseAcrylic(true);
|
_runtimeUseAcrylic = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize our font information.
|
// Initialize our font information.
|
||||||
const auto fontFace = _settings.FontFace();
|
const auto fontFace = _settings->FontFace();
|
||||||
const short fontHeight = ::base::saturated_cast<short>(_settings.FontSize());
|
const short fontHeight = ::base::saturated_cast<short>(_settings->FontSize());
|
||||||
const auto fontWeight = _settings.FontWeight();
|
const auto fontWeight = _settings->FontWeight();
|
||||||
// The font width doesn't terribly matter, we'll only be using the
|
// The font width doesn't terribly matter, we'll only be using the
|
||||||
// height to look it up
|
// height to look it up
|
||||||
// The other params here also largely don't matter.
|
// The other params here also largely don't matter.
|
||||||
|
@ -615,7 +625,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
_desiredFont = { _actualFont };
|
_desiredFont = { _actualFont };
|
||||||
|
|
||||||
// Update the terminal core with its new Core settings
|
// Update the terminal core with its new Core settings
|
||||||
_terminal->UpdateSettings(_settings);
|
_terminal->UpdateSettings(*_settings);
|
||||||
|
|
||||||
if (!_initializedTerminal)
|
if (!_initializedTerminal)
|
||||||
{
|
{
|
||||||
|
@ -624,8 +634,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
|
_renderEngine->SetForceFullRepaintRendering(_settings->ForceFullRepaintRendering());
|
||||||
_renderEngine->SetSoftwareRendering(_settings.SoftwareRendering());
|
_renderEngine->SetSoftwareRendering(_settings->SoftwareRendering());
|
||||||
|
// Inform the renderer of our opacity
|
||||||
|
_renderEngine->EnableTransparentBackground(_isBackgroundTransparent());
|
||||||
|
|
||||||
_updateAntiAliasingMode();
|
_updateAntiAliasingMode();
|
||||||
|
|
||||||
|
@ -642,21 +654,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Updates the appearance of the current terminal.
|
// - Updates the appearance of the current terminal.
|
||||||
// - INVARIANT: This method can only be called if the caller DOES NOT HAVE writing lock on the terminal.
|
// - INVARIANT: This method can only be called if the caller DOES NOT HAVE writing lock on the terminal.
|
||||||
void ControlCore::UpdateAppearance(const IControlAppearance& newAppearance)
|
void ControlCore::ApplyAppearance(const bool& focused)
|
||||||
{
|
{
|
||||||
auto lock = _terminal->LockForWriting();
|
auto lock = _terminal->LockForWriting();
|
||||||
|
const auto& newAppearance{ focused ? _settings->FocusedAppearance() : _settings->UnfocusedAppearance() };
|
||||||
// Update the terminal core with its new Core settings
|
// Update the terminal core with its new Core settings
|
||||||
_terminal->UpdateAppearance(newAppearance);
|
_terminal->UpdateAppearance(*newAppearance);
|
||||||
|
|
||||||
// Update DxEngine settings under the lock
|
// Update DxEngine settings under the lock
|
||||||
if (_renderEngine)
|
if (_renderEngine)
|
||||||
{
|
{
|
||||||
// Update DxEngine settings under the lock
|
// Update DxEngine settings under the lock
|
||||||
_renderEngine->SetSelectionBackground(til::color{ newAppearance.SelectionBackground() });
|
_renderEngine->SetSelectionBackground(til::color{ newAppearance->SelectionBackground() });
|
||||||
_renderEngine->SetRetroTerminalEffect(newAppearance.RetroTerminalEffect());
|
_renderEngine->SetRetroTerminalEffect(newAppearance->RetroTerminalEffect());
|
||||||
_renderEngine->SetPixelShaderPath(newAppearance.PixelShaderPath());
|
_renderEngine->SetPixelShaderPath(newAppearance->PixelShaderPath());
|
||||||
_renderEngine->SetIntenseIsBold(_settings.IntenseIsBold());
|
_renderEngine->SetIntenseIsBold(_settings->IntenseIsBold());
|
||||||
_renderer->TriggerRedrawAll();
|
_renderer->TriggerRedrawAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -664,8 +676,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void ControlCore::_updateAntiAliasingMode()
|
void ControlCore::_updateAntiAliasingMode()
|
||||||
{
|
{
|
||||||
D2D1_TEXT_ANTIALIAS_MODE mode;
|
D2D1_TEXT_ANTIALIAS_MODE mode;
|
||||||
|
// Update DxEngine's AntialiasingMode
|
||||||
switch (_settings.AntialiasingMode())
|
switch (_settings->AntialiasingMode())
|
||||||
{
|
{
|
||||||
case TextAntialiasingMode::Cleartype:
|
case TextAntialiasingMode::Cleartype:
|
||||||
mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
||||||
|
@ -701,7 +713,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
if (_renderEngine)
|
if (_renderEngine)
|
||||||
{
|
{
|
||||||
std::unordered_map<std::wstring_view, uint32_t> featureMap;
|
std::unordered_map<std::wstring_view, uint32_t> featureMap;
|
||||||
if (const auto fontFeatures = _settings.FontFeatures())
|
if (const auto fontFeatures = _settings->FontFeatures())
|
||||||
{
|
{
|
||||||
featureMap.reserve(fontFeatures.Size());
|
featureMap.reserve(fontFeatures.Size());
|
||||||
|
|
||||||
|
@ -711,7 +723,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::unordered_map<std::wstring_view, float> axesMap;
|
std::unordered_map<std::wstring_view, float> axesMap;
|
||||||
if (const auto fontAxes = _settings.FontAxes())
|
if (const auto fontAxes = _settings->FontAxes())
|
||||||
{
|
{
|
||||||
axesMap.reserve(fontAxes.Size());
|
axesMap.reserve(fontAxes.Size());
|
||||||
|
|
||||||
|
@ -753,8 +765,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
// Make sure we have a non-zero font size
|
// Make sure we have a non-zero font size
|
||||||
const auto newSize = std::max<short>(gsl::narrow_cast<short>(fontSize), 1);
|
const auto newSize = std::max<short>(gsl::narrow_cast<short>(fontSize), 1);
|
||||||
const auto fontFace = _settings.FontFace();
|
const auto fontFace = _settings->FontFace();
|
||||||
const auto fontWeight = _settings.FontWeight();
|
const auto fontWeight = _settings->FontWeight();
|
||||||
_actualFont = { fontFace, 0, fontWeight.Weight, { 0, newSize }, CP_UTF8, false };
|
_actualFont = { fontFace, 0, fontWeight.Weight, { 0, newSize }, CP_UTF8, false };
|
||||||
_actualFontFaceName = { fontFace };
|
_actualFontFaceName = { fontFace };
|
||||||
_desiredFont = { _actualFont };
|
_desiredFont = { _actualFont };
|
||||||
|
@ -779,7 +791,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - none
|
// - none
|
||||||
void ControlCore::ResetFontSize()
|
void ControlCore::ResetFontSize()
|
||||||
{
|
{
|
||||||
_setFontSize(_settings.FontSize());
|
_setFontSize(_settings->FontSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -991,7 +1003,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
TextBuffer::GenHTML(bufferData,
|
TextBuffer::GenHTML(bufferData,
|
||||||
_actualFont.GetUnscaledSize().Y,
|
_actualFont.GetUnscaledSize().Y,
|
||||||
_actualFont.GetFaceName(),
|
_actualFont.GetFaceName(),
|
||||||
til::color{ _settings.DefaultBackground() }) :
|
til::color{ _settings->DefaultBackground() }) :
|
||||||
"";
|
"";
|
||||||
|
|
||||||
// convert to RTF format
|
// convert to RTF format
|
||||||
|
@ -999,10 +1011,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
TextBuffer::GenRTF(bufferData,
|
TextBuffer::GenRTF(bufferData,
|
||||||
_actualFont.GetUnscaledSize().Y,
|
_actualFont.GetUnscaledSize().Y,
|
||||||
_actualFont.GetFaceName(),
|
_actualFont.GetFaceName(),
|
||||||
til::color{ _settings.DefaultBackground() }) :
|
til::color{ _settings->DefaultBackground() }) :
|
||||||
"";
|
"";
|
||||||
|
|
||||||
if (!_settings.CopyOnSelect())
|
if (!_settings->CopyOnSelect())
|
||||||
{
|
{
|
||||||
_terminal->ClearSelection();
|
_terminal->ClearSelection();
|
||||||
_renderer->TriggerSelection();
|
_renderer->TriggerSelection();
|
||||||
|
@ -1089,7 +1101,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
til::color ControlCore::BackgroundColor() const
|
til::color ControlCore::BackgroundColor() const
|
||||||
{
|
{
|
||||||
return _terminal->GetDefaultBackground();
|
// The Terminal internally stores it's BG with 0 opacity, so as to allow
|
||||||
|
// DX to paint the BG color transparently. We however don't want to leak
|
||||||
|
// that implementation detail.
|
||||||
|
return _terminal->GetDefaultBackground().with_alpha(0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -1246,7 +1261,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
bool ControlCore::CopyOnSelect() const
|
bool ControlCore::CopyOnSelect() const
|
||||||
{
|
{
|
||||||
return _settings.CopyOnSelect();
|
return _settings->CopyOnSelect();
|
||||||
}
|
}
|
||||||
|
|
||||||
Windows::Foundation::Collections::IVector<winrt::hstring> ControlCore::SelectedText(bool trimTrailingWhitespace) const
|
Windows::Foundation::Collections::IVector<winrt::hstring> ControlCore::SelectedText(bool trimTrailingWhitespace) const
|
||||||
|
@ -1304,16 +1319,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlCore::SetBackgroundOpacity(const double opacity)
|
|
||||||
{
|
|
||||||
if (_renderEngine)
|
|
||||||
{
|
|
||||||
auto lock = _terminal->LockForWriting();
|
|
||||||
const auto backgroundIsOpaque = opacity == 1.0 && _settings.BackgroundImage().empty();
|
|
||||||
_renderEngine->SetDefaultTextBackgroundOpacity(static_cast<float>(backgroundIsOpaque));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Asynchronously close our connection. The Connection will likely wait
|
// - Asynchronously close our connection. The Connection will likely wait
|
||||||
// until the attached process terminates before Close returns. If that's
|
// until the attached process terminates before Close returns. If that's
|
||||||
|
@ -1599,4 +1604,125 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
|
return VerifyVersionInfoW(&osver, VER_BUILDNUMBER, dwlConditionMask) != FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core::Scheme ControlCore::ColorScheme() const noexcept
|
||||||
|
{
|
||||||
|
Core::Scheme s;
|
||||||
|
|
||||||
|
// This part is definitely a hack.
|
||||||
|
//
|
||||||
|
// This function is usually used by the "Preview Color Scheme"
|
||||||
|
// functionality in TerminalPage. If we've got an unfocused appearance,
|
||||||
|
// then we've applied that appearance before this is even getting called
|
||||||
|
// (because the command palette is open with focus on top of us). If we
|
||||||
|
// return the _current_ colors now, we'll return out the _unfocused_
|
||||||
|
// colors. If we do that, and the user dismisses the command palette,
|
||||||
|
// then the scheme that will get restored is the _unfocused_ one, which
|
||||||
|
// is not what we want.
|
||||||
|
//
|
||||||
|
// So if that's the case, then let's grab the colors from the focused
|
||||||
|
// appearance as the scheme instead. We'll lose any current runtime
|
||||||
|
// changes to the color table, but those were already blown away when we
|
||||||
|
// switched to an unfocused appearance.
|
||||||
|
//
|
||||||
|
// IF WE DON'T HAVE AN UNFOCUSED APPEARANCE: then just ask the Terminal
|
||||||
|
// for it's current color table. That way, we can restore those colors
|
||||||
|
// back.
|
||||||
|
if (HasUnfocusedAppearance())
|
||||||
|
{
|
||||||
|
s.Foreground = _settings->FocusedAppearance()->DefaultForeground();
|
||||||
|
s.Background = _settings->FocusedAppearance()->DefaultBackground();
|
||||||
|
|
||||||
|
s.CursorColor = _settings->FocusedAppearance()->CursorColor();
|
||||||
|
|
||||||
|
s.Black = _settings->FocusedAppearance()->GetColorTableEntry(0);
|
||||||
|
s.Red = _settings->FocusedAppearance()->GetColorTableEntry(1);
|
||||||
|
s.Green = _settings->FocusedAppearance()->GetColorTableEntry(2);
|
||||||
|
s.Yellow = _settings->FocusedAppearance()->GetColorTableEntry(3);
|
||||||
|
s.Blue = _settings->FocusedAppearance()->GetColorTableEntry(4);
|
||||||
|
s.Purple = _settings->FocusedAppearance()->GetColorTableEntry(5);
|
||||||
|
s.Cyan = _settings->FocusedAppearance()->GetColorTableEntry(6);
|
||||||
|
s.White = _settings->FocusedAppearance()->GetColorTableEntry(7);
|
||||||
|
s.BrightBlack = _settings->FocusedAppearance()->GetColorTableEntry(8);
|
||||||
|
s.BrightRed = _settings->FocusedAppearance()->GetColorTableEntry(9);
|
||||||
|
s.BrightGreen = _settings->FocusedAppearance()->GetColorTableEntry(10);
|
||||||
|
s.BrightYellow = _settings->FocusedAppearance()->GetColorTableEntry(11);
|
||||||
|
s.BrightBlue = _settings->FocusedAppearance()->GetColorTableEntry(12);
|
||||||
|
s.BrightPurple = _settings->FocusedAppearance()->GetColorTableEntry(13);
|
||||||
|
s.BrightCyan = _settings->FocusedAppearance()->GetColorTableEntry(14);
|
||||||
|
s.BrightWhite = _settings->FocusedAppearance()->GetColorTableEntry(15);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s = _terminal->GetColorScheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This might be a tad bit of a hack. This event only gets called by set
|
||||||
|
// color scheme / preview color scheme, and in that case, we know the
|
||||||
|
// control _is_ focused.
|
||||||
|
s.SelectionBackground = _settings->FocusedAppearance()->SelectionBackground();
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Apply the given color scheme to this control. We'll take the colors out
|
||||||
|
// of it and apply them to our focused appearance, and update the terminal
|
||||||
|
// buffer with the new color table.
|
||||||
|
// - This is here to support the Set Color Scheme action, and the ability to
|
||||||
|
// preview schemes in the control.
|
||||||
|
// Arguments:
|
||||||
|
// - scheme: the collection of colors to apply.
|
||||||
|
// Return Value:
|
||||||
|
// - <none>
|
||||||
|
void ControlCore::ColorScheme(const Core::Scheme& scheme)
|
||||||
|
{
|
||||||
|
auto l{ _terminal->LockForWriting() };
|
||||||
|
|
||||||
|
_settings->FocusedAppearance()->DefaultForeground(scheme.Foreground);
|
||||||
|
_settings->FocusedAppearance()->DefaultBackground(scheme.Background);
|
||||||
|
_settings->FocusedAppearance()->CursorColor(scheme.CursorColor);
|
||||||
|
_settings->FocusedAppearance()->SelectionBackground(scheme.SelectionBackground);
|
||||||
|
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(0, scheme.Black);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(1, scheme.Red);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(2, scheme.Green);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(3, scheme.Yellow);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(4, scheme.Blue);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(5, scheme.Purple);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(6, scheme.Cyan);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(7, scheme.White);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(8, scheme.BrightBlack);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(9, scheme.BrightRed);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(10, scheme.BrightGreen);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(11, scheme.BrightYellow);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(12, scheme.BrightBlue);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(13, scheme.BrightPurple);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(14, scheme.BrightCyan);
|
||||||
|
_settings->FocusedAppearance()->SetColorTableEntry(15, scheme.BrightWhite);
|
||||||
|
|
||||||
|
_terminal->ApplyScheme(scheme);
|
||||||
|
_renderEngine->SetSelectionBackground(til::color{ _settings->SelectionBackground() });
|
||||||
|
|
||||||
|
_renderer->TriggerRedrawAll();
|
||||||
|
_BackgroundColorChangedHandlers(*this, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControlCore::HasUnfocusedAppearance() const
|
||||||
|
{
|
||||||
|
return _settings->HasUnfocusedAppearance();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControlCore::_isBackgroundTransparent()
|
||||||
|
{
|
||||||
|
// If we're:
|
||||||
|
// * Not fully opaque
|
||||||
|
// * On an acrylic background (of any opacity)
|
||||||
|
// * rendering on top of an image
|
||||||
|
//
|
||||||
|
// then the renderer should not render "default background" text with a
|
||||||
|
// fully opaque background. Doing that would cover up our nice
|
||||||
|
// transparency, or our acrylic, or our image.
|
||||||
|
return Opacity() < 1.0f || UseAcrylic() || !_settings->BackgroundImage().empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,23 +16,35 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ControlCore.g.h"
|
#include "ControlCore.g.h"
|
||||||
|
#include "ControlSettings.h"
|
||||||
#include "../../renderer/base/Renderer.hpp"
|
#include "../../renderer/base/Renderer.hpp"
|
||||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||||
#include "../buffer/out/search.h"
|
#include "../buffer/out/search.h"
|
||||||
#include "cppwinrt_utils.h"
|
#include "cppwinrt_utils.h"
|
||||||
|
|
||||||
|
#include <til/ticket_lock.h>
|
||||||
|
|
||||||
namespace ControlUnitTests
|
namespace ControlUnitTests
|
||||||
{
|
{
|
||||||
class ControlCoreTests;
|
class ControlCoreTests;
|
||||||
class ControlInteractivityTests;
|
class ControlInteractivityTests;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define RUNTIME_SETTING(type, name, setting) \
|
||||||
|
private: \
|
||||||
|
std::optional<type> _runtime##name{ std::nullopt }; \
|
||||||
|
void name(const type newValue) { _runtime##name = newValue; } \
|
||||||
|
\
|
||||||
|
public: \
|
||||||
|
type name() const { return til::coalesce_value(_runtime##name, setting); }
|
||||||
|
|
||||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
struct ControlCore : ControlCoreT<ControlCore>
|
struct ControlCore : ControlCoreT<ControlCore>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ControlCore(IControlSettings settings,
|
ControlCore(Control::IControlSettings settings,
|
||||||
|
Control::IControlAppearance unfocusedAppearance,
|
||||||
TerminalConnection::ITerminalConnection connection);
|
TerminalConnection::ITerminalConnection connection);
|
||||||
~ControlCore();
|
~ControlCore();
|
||||||
|
|
||||||
|
@ -41,8 +53,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
const double compositionScale);
|
const double compositionScale);
|
||||||
void EnablePainting();
|
void EnablePainting();
|
||||||
|
|
||||||
void UpdateSettings(const IControlSettings& settings);
|
void UpdateSettings(const Control::IControlSettings& settings, const IControlAppearance& newAppearance);
|
||||||
void UpdateAppearance(const IControlAppearance& newAppearance);
|
void ApplyAppearance(const bool& focused);
|
||||||
|
Control::IControlSettings Settings() { return *_settings; };
|
||||||
|
Control::IControlAppearance FocusedAppearance() const { return *_settings->FocusedAppearance(); };
|
||||||
|
Control::IControlAppearance UnfocusedAppearance() const { return *_settings->UnfocusedAppearance(); };
|
||||||
|
bool HasUnfocusedAppearance() const;
|
||||||
|
|
||||||
|
winrt::Microsoft::Terminal::Core::Scheme ColorScheme() const noexcept;
|
||||||
|
void ColorScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme);
|
||||||
|
|
||||||
void SizeChanged(const double width, const double height);
|
void SizeChanged(const double width, const double height);
|
||||||
void ScaleChanged(const double scale);
|
void ScaleChanged(const double scale);
|
||||||
uint64_t SwapChainHandle() const;
|
uint64_t SwapChainHandle() const;
|
||||||
|
@ -57,7 +77,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
uint16_t FontWeight() const noexcept;
|
uint16_t FontWeight() const noexcept;
|
||||||
|
|
||||||
til::color BackgroundColor() const;
|
til::color BackgroundColor() const;
|
||||||
void SetBackgroundOpacity(const double opacity);
|
|
||||||
|
|
||||||
void SendInput(const winrt::hstring& wstr);
|
void SendInput(const winrt::hstring& wstr);
|
||||||
void PasteText(const winrt::hstring& hstr);
|
void PasteText(const winrt::hstring& hstr);
|
||||||
|
@ -148,6 +167,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
static bool IsVintageOpacityAvailable() noexcept;
|
static bool IsVintageOpacityAvailable() noexcept;
|
||||||
|
|
||||||
|
RUNTIME_SETTING(double, Opacity, _settings->Opacity());
|
||||||
|
RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic());
|
||||||
|
|
||||||
// -------------------------------- WinRT Events ---------------------------------
|
// -------------------------------- WinRT Events ---------------------------------
|
||||||
// clang-format off
|
// clang-format off
|
||||||
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
|
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
|
||||||
|
@ -178,6 +200,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
event_token _connectionOutputEventToken;
|
event_token _connectionOutputEventToken;
|
||||||
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;
|
TerminalConnection::ITerminalConnection::StateChanged_revoker _connectionStateChangedRevoker;
|
||||||
|
|
||||||
|
winrt::com_ptr<ControlSettings> _settings{ nullptr };
|
||||||
|
|
||||||
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
|
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal{ nullptr };
|
||||||
|
|
||||||
// NOTE: _renderEngine must be ordered before _renderer.
|
// NOTE: _renderEngine must be ordered before _renderer.
|
||||||
|
@ -188,8 +212,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
std::unique_ptr<::Microsoft::Console::Render::IRenderEngine> _renderEngine{ nullptr };
|
std::unique_ptr<::Microsoft::Console::Render::IRenderEngine> _renderEngine{ nullptr };
|
||||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr };
|
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer{ nullptr };
|
||||||
|
|
||||||
IControlSettings _settings{ nullptr };
|
|
||||||
|
|
||||||
FontInfoDesired _desiredFont;
|
FontInfoDesired _desiredFont;
|
||||||
FontInfo _actualFont;
|
FontInfo _actualFont;
|
||||||
winrt::hstring _actualFontFaceName;
|
winrt::hstring _actualFontFaceName;
|
||||||
|
@ -249,6 +271,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
void _connectionOutputHandler(const hstring& hstr);
|
void _connectionOutputHandler(const hstring& hstr);
|
||||||
void _updateHoveredCell(const std::optional<til::point> terminalPosition);
|
void _updateHoveredCell(const std::optional<til::point> terminalPosition);
|
||||||
|
|
||||||
|
bool _isBackgroundTransparent();
|
||||||
|
|
||||||
inline bool _IsClosing() const noexcept
|
inline bool _IsClosing() const noexcept
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
|
@ -33,20 +33,27 @@ namespace Microsoft.Terminal.Control
|
||||||
[default_interface] runtimeclass ControlCore : ICoreState
|
[default_interface] runtimeclass ControlCore : ICoreState
|
||||||
{
|
{
|
||||||
ControlCore(IControlSettings settings,
|
ControlCore(IControlSettings settings,
|
||||||
|
IControlAppearance unfocusedAppearance,
|
||||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||||
|
|
||||||
Boolean Initialize(Double actualWidth,
|
Boolean Initialize(Double actualWidth,
|
||||||
Double actualHeight,
|
Double actualHeight,
|
||||||
Double compositionScale);
|
Double compositionScale);
|
||||||
|
|
||||||
void UpdateSettings(IControlSettings settings);
|
void UpdateSettings(IControlSettings settings, IControlAppearance appearance);
|
||||||
void UpdateAppearance(IControlAppearance appearance);
|
void ApplyAppearance(Boolean focused);
|
||||||
|
|
||||||
|
IControlSettings Settings { get; };
|
||||||
|
IControlAppearance FocusedAppearance { get; };
|
||||||
|
IControlAppearance UnfocusedAppearance { get; };
|
||||||
|
Boolean HasUnfocusedAppearance();
|
||||||
|
|
||||||
UInt64 SwapChainHandle { get; };
|
UInt64 SwapChainHandle { get; };
|
||||||
|
|
||||||
Windows.Foundation.Size FontSize { get; };
|
Windows.Foundation.Size FontSize { get; };
|
||||||
String FontFaceName { get; };
|
String FontFaceName { get; };
|
||||||
UInt16 FontWeight { get; };
|
UInt16 FontWeight { get; };
|
||||||
|
Double Opacity { get; };
|
||||||
|
|
||||||
Boolean TrySendKeyEvent(Int16 vkey,
|
Boolean TrySendKeyEvent(Int16 vkey,
|
||||||
Int16 scanCode,
|
Int16 scanCode,
|
||||||
|
@ -75,7 +82,6 @@ namespace Microsoft.Terminal.Control
|
||||||
void BlinkAttributeTick();
|
void BlinkAttributeTick();
|
||||||
void UpdatePatternLocations();
|
void UpdatePatternLocations();
|
||||||
void Search(String text, Boolean goForward, Boolean caseSensitive);
|
void Search(String text, Boolean goForward, Boolean caseSensitive);
|
||||||
void SetBackgroundOpacity(Double opacity);
|
|
||||||
Microsoft.Terminal.Core.Color BackgroundColor { get; };
|
Microsoft.Terminal.Core.Color BackgroundColor { get; };
|
||||||
|
|
||||||
Boolean HasSelection { get; };
|
Boolean HasSelection { get; };
|
||||||
|
|
|
@ -39,13 +39,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlInteractivity::ControlInteractivity(IControlSettings settings,
|
ControlInteractivity::ControlInteractivity(IControlSettings settings,
|
||||||
|
Control::IControlAppearance unfocusedAppearance,
|
||||||
TerminalConnection::ITerminalConnection connection) :
|
TerminalConnection::ITerminalConnection connection) :
|
||||||
_touchAnchor{ std::nullopt },
|
_touchAnchor{ std::nullopt },
|
||||||
_lastMouseClickTimestamp{},
|
_lastMouseClickTimestamp{},
|
||||||
_lastMouseClickPos{},
|
_lastMouseClickPos{},
|
||||||
_selectionNeedsToBeCopied{ false }
|
_selectionNeedsToBeCopied{ false }
|
||||||
{
|
{
|
||||||
_core = winrt::make_self<ControlCore>(settings, connection);
|
_core = winrt::make_self<ControlCore>(settings, unfocusedAppearance, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -641,4 +642,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
return _core->GetUiaData();
|
return _core->GetUiaData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Used by the TermControl to know if it should translate drag-dropped
|
||||||
|
// paths into WSL-friendly paths.
|
||||||
|
// Arguments:
|
||||||
|
// - <none>
|
||||||
|
// Return Value:
|
||||||
|
// - true if the connection we were created with was a WSL profile.
|
||||||
|
bool ControlInteractivity::ManglePathsForWsl()
|
||||||
|
{
|
||||||
|
return _core->Settings().ProfileSource() == L"Windows.Terminal.Wsl";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ControlInteractivity(IControlSettings settings,
|
ControlInteractivity(IControlSettings settings,
|
||||||
|
Control::IControlAppearance unfocusedAppearance,
|
||||||
TerminalConnection::ITerminalConnection connection);
|
TerminalConnection::ITerminalConnection connection);
|
||||||
|
|
||||||
void GotFocus();
|
void GotFocus();
|
||||||
|
@ -83,6 +84,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
const Windows::Foundation::IReference<CopyFormat>& formats);
|
const Windows::Foundation::IReference<CopyFormat>& formats);
|
||||||
void RequestPasteTextFromClipboard();
|
void RequestPasteTextFromClipboard();
|
||||||
void SetEndSelectionPoint(const til::point pixelPosition);
|
void SetEndSelectionPoint(const til::point pixelPosition);
|
||||||
|
bool ManglePathsForWsl();
|
||||||
|
|
||||||
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
|
||||||
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Microsoft.Terminal.Control
|
||||||
[default_interface] runtimeclass ControlInteractivity
|
[default_interface] runtimeclass ControlInteractivity
|
||||||
{
|
{
|
||||||
ControlInteractivity(IControlSettings settings,
|
ControlInteractivity(IControlSettings settings,
|
||||||
|
IControlAppearance unfocusedAppearance,
|
||||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||||
|
|
||||||
ControlCore Core { get; };
|
ControlCore Core { get; };
|
||||||
|
@ -58,6 +59,8 @@ namespace Microsoft.Terminal.Control
|
||||||
|
|
||||||
void UpdateScrollbar(Double newValue);
|
void UpdateScrollbar(Double newValue);
|
||||||
|
|
||||||
|
Boolean ManglePathsForWsl { get; };
|
||||||
|
|
||||||
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
|
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
|
event Windows.Foundation.TypedEventHandler<Object, ScrollPositionChangedArgs> ScrollPositionChanged;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
|
event Windows.Foundation.TypedEventHandler<Object, PasteFromClipboardEventArgs> PasteFromClipboard;
|
||||||
|
|
81
src/cascadia/TerminalControl/ControlSettings.h
Normal file
81
src/cascadia/TerminalControl/ControlSettings.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) Microsoft Corporation
|
||||||
|
Licensed under the MIT license.
|
||||||
|
--*/
|
||||||
|
#pragma once
|
||||||
|
#include "../../inc/cppwinrt_utils.h"
|
||||||
|
#include "../../inc/ControlProperties.h"
|
||||||
|
|
||||||
|
#include <DefaultSettings.h>
|
||||||
|
#include <conattrs.hpp>
|
||||||
|
#include "ControlAppearance.h"
|
||||||
|
|
||||||
|
using IFontFeatureMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, uint32_t>;
|
||||||
|
using IFontAxesMap = winrt::Windows::Foundation::Collections::IMap<winrt::hstring, float>;
|
||||||
|
|
||||||
|
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
{
|
||||||
|
struct ControlSettings : public winrt::implements<ControlSettings, Microsoft::Terminal::Control::IControlSettings, Microsoft::Terminal::Control::IControlAppearance, Microsoft::Terminal::Core::ICoreSettings, Microsoft::Terminal::Core::ICoreAppearance>
|
||||||
|
{
|
||||||
|
// Getters and setters for each *Setting member. We're not using
|
||||||
|
// WINRT_PROPERTY for these, because they actually exist inside the
|
||||||
|
// _focusedAppearance member. We don't need to reserve another member to
|
||||||
|
// hold them.
|
||||||
|
#define SETTINGS_GEN(type, name, ...) WINRT_PROPERTY(type, name, __VA_ARGS__);
|
||||||
|
CORE_SETTINGS(SETTINGS_GEN)
|
||||||
|
CONTROL_SETTINGS(SETTINGS_GEN)
|
||||||
|
#undef SETTINGS_GEN
|
||||||
|
|
||||||
|
private:
|
||||||
|
winrt::com_ptr<ControlAppearance> _unfocusedAppearance{ nullptr };
|
||||||
|
winrt::com_ptr<ControlAppearance> _focusedAppearance{ nullptr };
|
||||||
|
bool _hasUnfocusedAppearance{ false };
|
||||||
|
|
||||||
|
public:
|
||||||
|
ControlSettings(const Control::IControlSettings& settings,
|
||||||
|
const Control::IControlAppearance& unfocusedAppearance)
|
||||||
|
{
|
||||||
|
_hasUnfocusedAppearance = unfocusedAppearance != nullptr;
|
||||||
|
|
||||||
|
_focusedAppearance = winrt::make_self<implementation::ControlAppearance>(settings);
|
||||||
|
_unfocusedAppearance = unfocusedAppearance ?
|
||||||
|
winrt::make_self<implementation::ControlAppearance>(unfocusedAppearance) :
|
||||||
|
_focusedAppearance;
|
||||||
|
|
||||||
|
// Copy every value from the passed in settings, into us.
|
||||||
|
#define COPY_SETTING(type, name, ...) _##name = settings.name();
|
||||||
|
CORE_SETTINGS(COPY_SETTING)
|
||||||
|
CONTROL_SETTINGS(COPY_SETTING)
|
||||||
|
#undef COPY_SETTING
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::com_ptr<ControlAppearance> UnfocusedAppearance() { return _unfocusedAppearance; }
|
||||||
|
winrt::com_ptr<ControlAppearance> FocusedAppearance() { return _focusedAppearance; }
|
||||||
|
bool HasUnfocusedAppearance() { return _hasUnfocusedAppearance; }
|
||||||
|
|
||||||
|
// Getters and setters for each Appearance member. We're not using
|
||||||
|
// WINRT_PROPERTY for these, because they actually exist inside the
|
||||||
|
// _focusedAppearance member. We don't need to reserve another member to
|
||||||
|
// hold them.
|
||||||
|
//
|
||||||
|
// The Appearance members (including GetColorTableEntry below) are used
|
||||||
|
// when this ControlSettings is cast to a IControlAppearance or
|
||||||
|
// ICoreAppearance. In those cases, we'll always return the Focused
|
||||||
|
// appearance's version of the member. Callers who care about which
|
||||||
|
// appearance is being used should be more careful. Fortunately, this
|
||||||
|
// situation is generally only used when a control is first created, or
|
||||||
|
// when calling UpdateSettings.
|
||||||
|
#define APPEARANCE_GEN(type, name, ...) \
|
||||||
|
type name() const noexcept { return _focusedAppearance->name(); } \
|
||||||
|
void name(const type& value) noexcept { _focusedAppearance->name(value); }
|
||||||
|
|
||||||
|
CORE_APPEARANCE_SETTINGS(APPEARANCE_GEN)
|
||||||
|
CONTROL_APPEARANCE_SETTINGS(APPEARANCE_GEN)
|
||||||
|
#undef APPEARANCE_GEN
|
||||||
|
|
||||||
|
winrt::Microsoft::Terminal::Core::Color GetColorTableEntry(int32_t index) noexcept
|
||||||
|
{
|
||||||
|
return _focusedAppearance->GetColorTableEntry(index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,18 +5,18 @@ namespace Microsoft.Terminal.Control
|
||||||
{
|
{
|
||||||
interface IControlAppearance requires Microsoft.Terminal.Core.ICoreAppearance
|
interface IControlAppearance requires Microsoft.Terminal.Core.ICoreAppearance
|
||||||
{
|
{
|
||||||
Microsoft.Terminal.Core.Color SelectionBackground;
|
Microsoft.Terminal.Core.Color SelectionBackground { get; };
|
||||||
String BackgroundImage;
|
String BackgroundImage { get; };
|
||||||
Double BackgroundImageOpacity;
|
Double BackgroundImageOpacity { get; };
|
||||||
Windows.UI.Xaml.Media.Stretch BackgroundImageStretchMode;
|
Windows.UI.Xaml.Media.Stretch BackgroundImageStretchMode { get; };
|
||||||
Windows.UI.Xaml.HorizontalAlignment BackgroundImageHorizontalAlignment;
|
Windows.UI.Xaml.HorizontalAlignment BackgroundImageHorizontalAlignment { get; };
|
||||||
Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment;
|
Windows.UI.Xaml.VerticalAlignment BackgroundImageVerticalAlignment { get; };
|
||||||
Boolean IntenseIsBold;
|
Boolean IntenseIsBold { get; };
|
||||||
// IntenseIsBright is in Core Appearance
|
// IntenseIsBright is in Core Appearance
|
||||||
Double Opacity;
|
Double Opacity { get; };
|
||||||
|
|
||||||
// Experimental settings
|
// Experimental settings
|
||||||
Boolean RetroTerminalEffect;
|
Boolean RetroTerminalEffect { get; };
|
||||||
String PixelShaderPath;
|
String PixelShaderPath { get; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,34 +24,37 @@ namespace Microsoft.Terminal.Control
|
||||||
// TermControl's behavior. In these settings there is both the entirety
|
// TermControl's behavior. In these settings there is both the entirety
|
||||||
// of the Core ITerminalSettings interface, and any additional settings
|
// of the Core ITerminalSettings interface, and any additional settings
|
||||||
// for specifically the control.
|
// for specifically the control.
|
||||||
interface IControlSettings requires Microsoft.Terminal.Core.ICoreSettings, Microsoft.Terminal.Control.IControlAppearance
|
interface IControlSettings requires Microsoft.Terminal.Core.ICoreSettings,
|
||||||
|
Microsoft.Terminal.Control.IControlAppearance
|
||||||
{
|
{
|
||||||
String ProfileName;
|
String ProfileName;
|
||||||
String ProfileSource;
|
String ProfileSource;
|
||||||
|
|
||||||
Boolean UseAcrylic;
|
Boolean UseAcrylic { get; };
|
||||||
ScrollbarState ScrollState;
|
ScrollbarState ScrollState { get; };
|
||||||
Boolean UseAtlasEngine;
|
|
||||||
String FontFace;
|
|
||||||
Int32 FontSize;
|
|
||||||
Windows.UI.Text.FontWeight FontWeight;
|
|
||||||
String Padding;
|
|
||||||
Windows.Foundation.Collections.IMap<String, UInt32> FontFeatures;
|
|
||||||
Windows.Foundation.Collections.IMap<String, Single> FontAxes;
|
|
||||||
|
|
||||||
Microsoft.Terminal.Control.IKeyBindings KeyBindings;
|
Boolean UseAtlasEngine { get; };
|
||||||
|
|
||||||
Boolean CopyOnSelect;
|
String FontFace { get; };
|
||||||
Boolean FocusFollowMouse;
|
Int32 FontSize { get; };
|
||||||
|
Windows.UI.Text.FontWeight FontWeight { get; };
|
||||||
|
String Padding { get; };
|
||||||
|
Windows.Foundation.Collections.IMap<String, UInt32> FontFeatures { get; };
|
||||||
|
Windows.Foundation.Collections.IMap<String, Single> FontAxes { get; };
|
||||||
|
|
||||||
String Commandline;
|
Microsoft.Terminal.Control.IKeyBindings KeyBindings { get; };
|
||||||
String StartingDirectory;
|
|
||||||
String EnvironmentVariables;
|
|
||||||
|
|
||||||
TextAntialiasingMode AntialiasingMode;
|
Boolean CopyOnSelect { get; };
|
||||||
|
Boolean FocusFollowMouse { get; };
|
||||||
|
|
||||||
|
String Commandline { get; };
|
||||||
|
String StartingDirectory { get; };
|
||||||
|
String EnvironmentVariables { get; };
|
||||||
|
|
||||||
|
TextAntialiasingMode AntialiasingMode { get; };
|
||||||
|
|
||||||
// Experimental Settings
|
// Experimental Settings
|
||||||
Boolean ForceFullRepaintRendering;
|
Boolean ForceFullRepaintRendering { get; };
|
||||||
Boolean SoftwareRendering;
|
Boolean SoftwareRendering { get; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,5 +22,7 @@ namespace Microsoft.Terminal.Control
|
||||||
Boolean BracketedPasteEnabled { get; };
|
Boolean BracketedPasteEnabled { get; };
|
||||||
|
|
||||||
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
|
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
|
||||||
|
|
||||||
|
Microsoft.Terminal.Core.Scheme ColorScheme { get; set; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,8 @@ DEFINE_ENUM_FLAG_OPERATORS(winrt::Microsoft::Terminal::Control::MouseButtonState
|
||||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
TermControl::TermControl(IControlSettings settings,
|
TermControl::TermControl(IControlSettings settings,
|
||||||
|
Control::IControlAppearance unfocusedAppearance,
|
||||||
TerminalConnection::ITerminalConnection connection) :
|
TerminalConnection::ITerminalConnection connection) :
|
||||||
_settings{ settings },
|
|
||||||
_isInternalScrollBarUpdate{ false },
|
_isInternalScrollBarUpdate{ false },
|
||||||
_autoScrollVelocity{ 0 },
|
_autoScrollVelocity{ 0 },
|
||||||
_autoScrollingPointerPoint{ std::nullopt },
|
_autoScrollingPointerPoint{ std::nullopt },
|
||||||
|
@ -61,7 +61,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_interactivity = winrt::make<implementation::ControlInteractivity>(settings, connection);
|
_interactivity = winrt::make<implementation::ControlInteractivity>(settings, unfocusedAppearance, connection);
|
||||||
_core = _interactivity.Core();
|
_core = _interactivity.Core();
|
||||||
|
|
||||||
// These events might all be triggered by the connection, but that
|
// These events might all be triggered by the connection, but that
|
||||||
|
@ -77,7 +77,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// These callbacks can only really be triggered by UI interactions. So
|
// These callbacks can only really be triggered by UI interactions. So
|
||||||
// they don't need weak refs - they can't be triggered unless we're
|
// they don't need weak refs - they can't be triggered unless we're
|
||||||
// alive.
|
// alive.
|
||||||
_core.BackgroundColorChanged({ this, &TermControl::_BackgroundColorChangedHandler });
|
_core.BackgroundColorChanged({ this, &TermControl::_coreBackgroundColorChanged });
|
||||||
_core.FontSizeChanged({ this, &TermControl::_coreFontSizeChanged });
|
_core.FontSizeChanged({ this, &TermControl::_coreFontSizeChanged });
|
||||||
_core.TransparencyChanged({ this, &TermControl::_coreTransparencyChanged });
|
_core.TransparencyChanged({ this, &TermControl::_coreTransparencyChanged });
|
||||||
_core.RaiseNotice({ this, &TermControl::_coreRaisedNotice });
|
_core.RaiseNotice({ this, &TermControl::_coreRaisedNotice });
|
||||||
|
@ -144,7 +144,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
|
||||||
_autoScrollTimer.Tick({ this, &TermControl::_UpdateAutoScroll });
|
_autoScrollTimer.Tick({ this, &TermControl::_UpdateAutoScroll });
|
||||||
|
|
||||||
_ApplyUISettings(_settings);
|
_ApplyUISettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -229,11 +229,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
this->Focus(FocusState::Programmatic);
|
this->Focus(FocusState::Programmatic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
winrt::fire_and_forget TermControl::UpdateControlSettings(IControlSettings settings)
|
||||||
|
{
|
||||||
|
return UpdateControlSettings(settings, _core.UnfocusedAppearance());
|
||||||
|
}
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Given Settings having been updated, applies the settings to the current terminal.
|
// - Given Settings having been updated, applies the settings to the current terminal.
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <none>
|
||||||
winrt::fire_and_forget TermControl::UpdateSettings()
|
winrt::fire_and_forget TermControl::UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance)
|
||||||
{
|
{
|
||||||
auto weakThis{ get_weak() };
|
auto weakThis{ get_weak() };
|
||||||
|
|
||||||
|
@ -241,21 +245,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// terminal.
|
// terminal.
|
||||||
co_await winrt::resume_foreground(Dispatcher());
|
co_await winrt::resume_foreground(Dispatcher());
|
||||||
|
|
||||||
_UpdateSettingsFromUIThread(_settings);
|
_core.UpdateSettings(settings, unfocusedAppearance);
|
||||||
|
|
||||||
auto appearance = _settings.try_as<IControlAppearance>();
|
_UpdateSettingsFromUIThread();
|
||||||
if (!_focused && _UnfocusedAppearance)
|
|
||||||
{
|
_UpdateAppearanceFromUIThread(_focused ? _core.FocusedAppearance() : _core.UnfocusedAppearance());
|
||||||
appearance = _UnfocusedAppearance;
|
|
||||||
}
|
|
||||||
_UpdateAppearanceFromUIThread(appearance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Dispatches a call to the UI thread and updates the appearance
|
// - Dispatches a call to the UI thread and updates the appearance
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - newAppearance: the new appearance to set
|
// - newAppearance: the new appearance to set
|
||||||
winrt::fire_and_forget TermControl::UpdateAppearance(const IControlAppearance newAppearance)
|
winrt::fire_and_forget TermControl::UpdateAppearance(IControlAppearance newAppearance)
|
||||||
{
|
{
|
||||||
// Dispatch a call to the UI thread
|
// Dispatch a call to the UI thread
|
||||||
co_await winrt::resume_foreground(Dispatcher());
|
co_await winrt::resume_foreground(Dispatcher());
|
||||||
|
@ -271,17 +272,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - INVARIANT: This method must be called from the UI thread.
|
// - INVARIANT: This method must be called from the UI thread.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - newSettings: the new settings to set
|
// - newSettings: the new settings to set
|
||||||
void TermControl::_UpdateSettingsFromUIThread(IControlSettings newSettings)
|
void TermControl::_UpdateSettingsFromUIThread()
|
||||||
{
|
{
|
||||||
if (_IsClosing())
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_core.UpdateSettings(_settings);
|
|
||||||
|
|
||||||
// Update our control settings
|
// Update our control settings
|
||||||
_ApplyUISettings(_settings);
|
_ApplyUISettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -289,7 +288,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - INVARIANT: This method must be called from the UI thread.
|
// - INVARIANT: This method must be called from the UI thread.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - newAppearance: the new appearance to set
|
// - newAppearance: the new appearance to set
|
||||||
void TermControl::_UpdateAppearanceFromUIThread(IControlAppearance newAppearance)
|
void TermControl::_UpdateAppearanceFromUIThread(Control::IControlAppearance newAppearance)
|
||||||
{
|
{
|
||||||
if (_IsClosing())
|
if (_IsClosing())
|
||||||
{
|
{
|
||||||
|
@ -300,6 +299,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
// Update our control settings
|
// Update our control settings
|
||||||
const auto bg = newAppearance.DefaultBackground();
|
const auto bg = newAppearance.DefaultBackground();
|
||||||
|
|
||||||
|
// In the future, this might need to be changed to a
|
||||||
|
// _InitializeBackgroundBrush call instead, because we may need to
|
||||||
|
// switch from a solid color brush to an acrylic one.
|
||||||
_changeBackgroundColor(bg);
|
_changeBackgroundColor(bg);
|
||||||
|
|
||||||
// Set TSF Foreground
|
// Set TSF Foreground
|
||||||
|
@ -307,7 +310,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
foregroundBrush.Color(static_cast<til::color>(newAppearance.DefaultForeground()));
|
foregroundBrush.Color(static_cast<til::color>(newAppearance.DefaultForeground()));
|
||||||
TSFInputControl().Foreground(foregroundBrush);
|
TSFInputControl().Foreground(foregroundBrush);
|
||||||
|
|
||||||
_core.UpdateAppearance(newAppearance);
|
_core.ApplyAppearance(_focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
|
@ -331,7 +334,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Style our UI elements based on the values in our _settings, and set up
|
// - Style our UI elements based on the values in our settings, and set up
|
||||||
// other control-specific settings. This method will be called whenever
|
// other control-specific settings. This method will be called whenever
|
||||||
// the settings are reloaded.
|
// the settings are reloaded.
|
||||||
// * Calls _InitializeBackgroundBrush to set up the Xaml brush responsible
|
// * Calls _InitializeBackgroundBrush to set up the Xaml brush responsible
|
||||||
|
@ -342,21 +345,21 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - <none>
|
// - <none>
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <none>
|
||||||
void TermControl::_ApplyUISettings(const IControlSettings& newSettings)
|
void TermControl::_ApplyUISettings()
|
||||||
{
|
{
|
||||||
_InitializeBackgroundBrush();
|
_InitializeBackgroundBrush();
|
||||||
|
|
||||||
const auto bg = newSettings.DefaultBackground();
|
// settings might be out-of-proc in the future
|
||||||
_changeBackgroundColor(bg);
|
auto settings{ _core.Settings() };
|
||||||
|
|
||||||
// Apply padding as swapChainPanel's margin
|
// Apply padding as swapChainPanel's margin
|
||||||
const auto newMargin = ParseThicknessFromPadding(newSettings.Padding());
|
const auto newMargin = ParseThicknessFromPadding(settings.Padding());
|
||||||
SwapChainPanel().Margin(newMargin);
|
SwapChainPanel().Margin(newMargin);
|
||||||
|
|
||||||
TSFInputControl().Margin(newMargin);
|
TSFInputControl().Margin(newMargin);
|
||||||
|
|
||||||
// Apply settings for scrollbar
|
// Apply settings for scrollbar
|
||||||
if (newSettings.ScrollState() == ScrollbarState::Hidden)
|
if (settings.ScrollState() == ScrollbarState::Hidden)
|
||||||
{
|
{
|
||||||
// In the scenario where the user has turned off the OS setting to automatically hide scrollbars, the
|
// In the scenario where the user has turned off the OS setting to automatically hide scrollbars, the
|
||||||
// Terminal scrollbar would still be visible; so, we need to set the control's visibility accordingly to
|
// Terminal scrollbar would still be visible; so, we need to set the control's visibility accordingly to
|
||||||
|
@ -440,16 +443,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// use bgcolor as acrylic's tint
|
// use bgcolor as acrylic's tint
|
||||||
// - Avoids image flickering and acrylic brush redraw if settings are changed
|
// - Avoids image flickering and acrylic brush redraw if settings are changed
|
||||||
// but the appropriate brush is still in place.
|
// but the appropriate brush is still in place.
|
||||||
// - Does not apply background color outside of acrylic mode;
|
|
||||||
// _BackgroundColorChanged must be called to do so.
|
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - <none>
|
// - <none>
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <none>
|
||||||
void TermControl::_InitializeBackgroundBrush()
|
void TermControl::_InitializeBackgroundBrush()
|
||||||
{
|
{
|
||||||
auto appearance = _settings.try_as<IControlAppearance>();
|
auto settings{ _core.Settings() };
|
||||||
if (_settings.UseAcrylic())
|
auto bgColor = til::color{ _core.FocusedAppearance().DefaultBackground() }.with_alpha(0xff);
|
||||||
|
if (settings.UseAcrylic())
|
||||||
{
|
{
|
||||||
// See if we've already got an acrylic background brush
|
// See if we've already got an acrylic background brush
|
||||||
// to avoid the flicker when setting up a new one
|
// to avoid the flicker when setting up a new one
|
||||||
|
@ -464,53 +466,55 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
// see GH#1082: Initialize background color so we don't get a
|
// see GH#1082: Initialize background color so we don't get a
|
||||||
// fade/flash when _BackgroundColorChanged is called
|
// fade/flash when _BackgroundColorChanged is called
|
||||||
auto bgColor = til::color{ _settings.DefaultBackground() }.with_alpha(0xff);
|
|
||||||
|
|
||||||
acrylic.FallbackColor(bgColor);
|
acrylic.FallbackColor(bgColor);
|
||||||
acrylic.TintColor(bgColor);
|
acrylic.TintColor(bgColor);
|
||||||
|
|
||||||
// Apply brush settings
|
// Apply brush settings
|
||||||
acrylic.TintOpacity(appearance.Opacity());
|
acrylic.TintOpacity(_core.Opacity());
|
||||||
|
|
||||||
// Apply brush to control if it's not already there
|
// Apply brush to control if it's not already there
|
||||||
if (RootGrid().Background() != acrylic)
|
if (RootGrid().Background() != acrylic)
|
||||||
{
|
{
|
||||||
RootGrid().Background(acrylic);
|
RootGrid().Background(acrylic);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GH#5098: Inform the engine of the new opacity of the default text background.
|
|
||||||
_core.SetBackgroundOpacity(appearance.Opacity());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Media::SolidColorBrush solidColor{};
|
Media::SolidColorBrush solidColor{};
|
||||||
solidColor.Opacity(_settings.Opacity());
|
solidColor.Opacity(_core.Opacity());
|
||||||
RootGrid().Background(solidColor);
|
solidColor.Color(bgColor);
|
||||||
|
|
||||||
// GH#5098: Inform the engine of the new opacity of the default text background.
|
RootGrid().Background(solidColor);
|
||||||
_core.SetBackgroundOpacity(appearance.Opacity());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Style the background of the control with the provided background color
|
// - Handler for the core's BackgroundColorChanged event. Updates the color
|
||||||
|
// of our background brush to match.
|
||||||
|
// - Hops over to the UI thread to do this work.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - color: The background color to use as a uint32 (aka DWORD COLORREF)
|
// <unused>
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <none>
|
||||||
void TermControl::_BackgroundColorChangedHandler(const IInspectable& /*sender*/,
|
winrt::fire_and_forget TermControl::_coreBackgroundColorChanged(const IInspectable& /*sender*/,
|
||||||
const IInspectable& /*args*/)
|
const IInspectable& /*args*/)
|
||||||
|
{
|
||||||
|
auto weakThis{ get_weak() };
|
||||||
|
co_await winrt::resume_foreground(Dispatcher());
|
||||||
|
if (auto control{ weakThis.get() })
|
||||||
{
|
{
|
||||||
til::color newBgColor{ _core.BackgroundColor() };
|
til::color newBgColor{ _core.BackgroundColor() };
|
||||||
_changeBackgroundColor(newBgColor);
|
_changeBackgroundColor(newBgColor);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
winrt::fire_and_forget TermControl::_changeBackgroundColor(const til::color bg)
|
// Method Description:
|
||||||
{
|
// - Update the color of the background brush we're using. This does _not_
|
||||||
auto weakThis{ get_weak() };
|
// update the opacity, or what type of brush it is.
|
||||||
co_await winrt::resume_foreground(Dispatcher());
|
// - INVARIANT: This needs to be called on the UI thread.
|
||||||
|
// Arguments:
|
||||||
if (auto control{ weakThis.get() })
|
// - bg: the new color to use as the background color.
|
||||||
|
void TermControl::_changeBackgroundColor(const til::color bg)
|
||||||
{
|
{
|
||||||
if (auto acrylic = RootGrid().Background().try_as<Media::AcrylicBrush>())
|
if (auto acrylic = RootGrid().Background().try_as<Media::AcrylicBrush>())
|
||||||
{
|
{
|
||||||
|
@ -524,6 +528,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
solidColor.Opacity(originalOpacity);
|
solidColor.Opacity(originalOpacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Description:
|
||||||
|
// - Update the opacity of the background brush we're using. This does _not_
|
||||||
|
// update the color, or what type of brush it is.
|
||||||
|
// - INVARIANT: This needs to be called on the UI thread.
|
||||||
|
void TermControl::_changeBackgroundOpacity()
|
||||||
|
{
|
||||||
|
const auto opacity{ _core.Opacity() };
|
||||||
|
if (auto acrylic = RootGrid().Background().try_as<Media::AcrylicBrush>())
|
||||||
|
{
|
||||||
|
acrylic.TintOpacity(opacity);
|
||||||
|
}
|
||||||
|
else if (auto solidColor = RootGrid().Background().try_as<Media::SolidColorBrush>())
|
||||||
|
{
|
||||||
|
solidColor.Opacity(opacity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TermControl::~TermControl()
|
TermControl::~TermControl()
|
||||||
|
@ -618,7 +638,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
|
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
|
||||||
{
|
{
|
||||||
message = { fmt::format(std::wstring_view{ RS_(L"PixelShaderNotFound") },
|
message = { fmt::format(std::wstring_view{ RS_(L"PixelShaderNotFound") },
|
||||||
_settings.PixelShaderPath()) };
|
(_focused ? _core.FocusedAppearance() : _core.UnfocusedAppearance()).PixelShaderPath()) };
|
||||||
}
|
}
|
||||||
else if (D2DERR_SHADER_COMPILE_FAILED == hr)
|
else if (D2DERR_SHADER_COMPILE_FAILED == hr)
|
||||||
{
|
{
|
||||||
|
@ -740,7 +760,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that the renderer is set up, update the appearance for initialization
|
// Now that the renderer is set up, update the appearance for initialization
|
||||||
_UpdateAppearanceFromUIThread(_settings);
|
_UpdateAppearanceFromUIThread(_core.FocusedAppearance());
|
||||||
|
|
||||||
_initializedTerminal = true;
|
_initializedTerminal = true;
|
||||||
|
|
||||||
|
@ -812,7 +832,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// This is required as part of GH#638.
|
// This is required as part of GH#638.
|
||||||
// Or do so for alt+space; only send to terminal when explicitly unbound
|
// Or do so for alt+space; only send to terminal when explicitly unbound
|
||||||
// That is part of #GH7125
|
// That is part of #GH7125
|
||||||
auto bindings{ _settings.KeyBindings() };
|
auto bindings{ _core.Settings().KeyBindings() };
|
||||||
bool isUnbound = false;
|
bool isUnbound = false;
|
||||||
const KeyChord kc = {
|
const KeyChord kc = {
|
||||||
modifiers.IsCtrlPressed(),
|
modifiers.IsCtrlPressed(),
|
||||||
|
@ -957,7 +977,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - modifiers: The ControlKeyStates representing the modifier key states.
|
// - modifiers: The ControlKeyStates representing the modifier key states.
|
||||||
bool TermControl::_TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const
|
bool TermControl::_TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const
|
||||||
{
|
{
|
||||||
auto bindings = _settings.KeyBindings();
|
// TODO: GH#5000
|
||||||
|
// The Core owning the keybindings is weird. That's for sure. In the
|
||||||
|
// future, we may want to pass the keybindings into the control
|
||||||
|
// separately, so the control can have a pointer to an in-proc
|
||||||
|
// Keybindings object, rather than routing through the ControlCore.
|
||||||
|
// (see GH#5000)
|
||||||
|
auto bindings = _core.Settings().KeyBindings();
|
||||||
if (!bindings)
|
if (!bindings)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -1136,7 +1162,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
const auto pixelPosition = _toTerminalOrigin(cursorPosition);
|
const auto pixelPosition = _toTerminalOrigin(cursorPosition);
|
||||||
const auto type = ptr.PointerDeviceType();
|
const auto type = ptr.PointerDeviceType();
|
||||||
|
|
||||||
if (!_focused && _settings.FocusFollowMouse())
|
if (!_focused && _core.Settings().FocusFollowMouse())
|
||||||
{
|
{
|
||||||
_FocusFollowMouseRequestedHandlers(*this, nullptr);
|
_FocusFollowMouseRequestedHandlers(*this, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -1304,7 +1330,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
// - Called in response to the core's TransparencyChanged event. We'll use
|
// - Called in response to the core's TransparencyChanged event. We'll use
|
||||||
// this to update our background brush.
|
// this to update our background brush.
|
||||||
// - The Core should have already updated the TintOpacity and UseAcrylic
|
// - The Core should have already updated the TintOpacity and UseAcrylic
|
||||||
// properties in the _settings.
|
// properties in the _settings->
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - <unused>
|
// - <unused>
|
||||||
// Return Value:
|
// Return Value:
|
||||||
|
@ -1315,9 +1341,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
co_await resume_foreground(Dispatcher());
|
co_await resume_foreground(Dispatcher());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_InitializeBackgroundBrush();
|
_changeBackgroundOpacity();
|
||||||
const auto bg = _settings.DefaultBackground();
|
|
||||||
_changeBackgroundColor(bg);
|
|
||||||
}
|
}
|
||||||
CATCH_LOG();
|
CATCH_LOG();
|
||||||
}
|
}
|
||||||
|
@ -1524,12 +1548,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
_blinkTimer->Start();
|
_blinkTimer->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only update the appearance here if an unfocused config exists -
|
// Only update the appearance here if an unfocused config exists - if an
|
||||||
// if an unfocused config does not exist then we never would have switched
|
// unfocused config does not exist then we never would have switched
|
||||||
// appearances anyway so there's no need to switch back upon gaining focus
|
// appearances anyway so there's no need to switch back upon gaining
|
||||||
if (_UnfocusedAppearance)
|
// focus
|
||||||
|
if (_core.HasUnfocusedAppearance())
|
||||||
{
|
{
|
||||||
UpdateAppearance(_settings);
|
UpdateAppearance(_core.FocusedAppearance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1571,9 +1596,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
// Check if there is an unfocused config we should set the appearance to
|
// Check if there is an unfocused config we should set the appearance to
|
||||||
// upon losing focus
|
// upon losing focus
|
||||||
if (_UnfocusedAppearance)
|
if (_core.HasUnfocusedAppearance())
|
||||||
{
|
{
|
||||||
UpdateAppearance(_UnfocusedAppearance);
|
UpdateAppearance(_core.UnfocusedAppearance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1722,7 +1747,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
hstring TermControl::GetProfileName() const
|
hstring TermControl::GetProfileName() const
|
||||||
{
|
{
|
||||||
return _settings.ProfileName();
|
return _core.Settings().ProfileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
hstring TermControl::WorkingDirectory() const
|
hstring TermControl::WorkingDirectory() const
|
||||||
|
@ -1944,7 +1969,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
double width = fontSize.Width;
|
double width = fontSize.Width;
|
||||||
double height = fontSize.Height;
|
double height = fontSize.Height;
|
||||||
// Reserve additional space if scrollbar is intended to be visible
|
// Reserve additional space if scrollbar is intended to be visible
|
||||||
if (_settings.ScrollState() == ScrollbarState::Visible)
|
if (_core.Settings().ScrollState() == ScrollbarState::Visible)
|
||||||
{
|
{
|
||||||
width += ScrollBar().ActualWidth();
|
width += ScrollBar().ActualWidth();
|
||||||
}
|
}
|
||||||
|
@ -1965,7 +1990,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
const winrt::Windows::Foundation::Size minSize{ 1, 1 };
|
const winrt::Windows::Foundation::Size minSize{ 1, 1 };
|
||||||
const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
|
const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
|
||||||
const auto dpi = ::base::saturated_cast<uint32_t>(USER_DEFAULT_SCREEN_DPI * scaleFactor);
|
const auto dpi = ::base::saturated_cast<uint32_t>(USER_DEFAULT_SCREEN_DPI * scaleFactor);
|
||||||
return GetProposedDimensions(_settings, dpi, minSize);
|
|
||||||
|
return GetProposedDimensions(_core.Settings(), dpi, minSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1987,7 +2013,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
padding.Left + padding.Right :
|
padding.Left + padding.Right :
|
||||||
padding.Top + padding.Bottom);
|
padding.Top + padding.Bottom);
|
||||||
|
|
||||||
if (widthOrHeight && _settings.ScrollState() == ScrollbarState::Visible)
|
if (widthOrHeight && _core.Settings().ScrollState() == ScrollbarState::Visible)
|
||||||
{
|
{
|
||||||
nonTerminalArea += gsl::narrow_cast<float>(ScrollBar().ActualWidth());
|
nonTerminalArea += gsl::narrow_cast<float>(ScrollBar().ActualWidth());
|
||||||
}
|
}
|
||||||
|
@ -2270,7 +2296,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
std::wstring fullPath{ item.Path() };
|
std::wstring fullPath{ item.Path() };
|
||||||
|
|
||||||
// Fix path for WSL
|
// Fix path for WSL
|
||||||
if (_settings.ProfileSource() == L"Windows.Terminal.Wsl")
|
// In the fullness of time, we should likely plumb this up
|
||||||
|
// to the TerminalApp layer, and have it make the decision
|
||||||
|
// if this control should have it's path mangled (and do the
|
||||||
|
// mangling), rather than exposing the source concept to the
|
||||||
|
// Control layer.
|
||||||
|
//
|
||||||
|
// However, it's likely that the control layer may need to
|
||||||
|
// know about the source anyways in the future, to support
|
||||||
|
// GH#3158
|
||||||
|
if (_interactivity.ManglePathsForWsl())
|
||||||
{
|
{
|
||||||
std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/');
|
std::replace(fullPath.begin(), fullPath.end(), L'\\', L'/');
|
||||||
|
|
||||||
|
@ -2417,12 +2452,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
IControlSettings TermControl::Settings() const
|
IControlSettings TermControl::Settings() const
|
||||||
{
|
{
|
||||||
return _settings;
|
// TODO: GH#5000
|
||||||
}
|
// We still need this in a couple places:
|
||||||
|
// - Pane.cpp uses this for parsing out the StartingTitle, Commandline,
|
||||||
void TermControl::Settings(IControlSettings newSettings)
|
// etc for Pane::GetTerminalArgsForPane.
|
||||||
{
|
// - TerminalTab::_CreateToolTipTitle uses the ProfileName for the
|
||||||
_settings = newSettings;
|
// tooltip for the tab.
|
||||||
|
//
|
||||||
|
// These both happen on the UI thread right now. In the future, when we
|
||||||
|
// have to hop across the process boundary to get at the core settings,
|
||||||
|
// it may make sense to cache these values inside the TermControl
|
||||||
|
// itself, so it can do the hop once when it's first setup, rather than
|
||||||
|
// when it's needed by the UI thread.
|
||||||
|
return _core.Settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
Windows::Foundation::IReference<winrt::Windows::UI::Color> TermControl::TabColor() noexcept
|
Windows::Foundation::IReference<winrt::Windows::UI::Color> TermControl::TabColor() noexcept
|
||||||
|
@ -2645,4 +2687,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
return _core.ReadEntireBuffer();
|
return _core.ReadEntireBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Core::Scheme TermControl::ColorScheme() const noexcept
|
||||||
|
{
|
||||||
|
return _core.ColorScheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TermControl::ColorScheme(const Core::Scheme& scheme) const noexcept
|
||||||
|
{
|
||||||
|
_core.ColorScheme(scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
Media::Brush TermControl::BackgroundBrush()
|
||||||
|
{
|
||||||
|
return RootGrid().Background();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
{
|
{
|
||||||
struct TermControl : TermControlT<TermControl>
|
struct TermControl : TermControlT<TermControl>
|
||||||
{
|
{
|
||||||
TermControl(IControlSettings settings, TerminalConnection::ITerminalConnection connection);
|
TermControl(IControlSettings settings,
|
||||||
|
Control::IControlAppearance unfocusedAppearance,
|
||||||
|
TerminalConnection::ITerminalConnection connection);
|
||||||
|
|
||||||
winrt::fire_and_forget UpdateSettings();
|
winrt::fire_and_forget UpdateControlSettings(Control::IControlSettings settings);
|
||||||
winrt::fire_and_forget UpdateAppearance(const IControlAppearance newAppearance);
|
winrt::fire_and_forget UpdateControlSettings(Control::IControlSettings settings, Control::IControlAppearance unfocusedAppearance);
|
||||||
|
IControlSettings Settings() const;
|
||||||
|
|
||||||
hstring GetProfileName() const;
|
hstring GetProfileName() const;
|
||||||
|
|
||||||
|
@ -88,9 +91,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
|
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
|
||||||
const Windows::UI::Xaml::Thickness GetPadding();
|
const Windows::UI::Xaml::Thickness GetPadding();
|
||||||
|
|
||||||
IControlSettings Settings() const;
|
|
||||||
void Settings(IControlSettings newSettings);
|
|
||||||
|
|
||||||
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi);
|
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi);
|
||||||
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars);
|
static Windows::Foundation::Size GetProposedDimensions(IControlSettings const& settings, const uint32_t dpi, const winrt::Windows::Foundation::Size& initialSizeInChars);
|
||||||
|
|
||||||
|
@ -105,6 +105,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
hstring ReadEntireBuffer() const;
|
hstring ReadEntireBuffer() const;
|
||||||
|
|
||||||
|
winrt::Microsoft::Terminal::Core::Scheme ColorScheme() const noexcept;
|
||||||
|
void ColorScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme) const noexcept;
|
||||||
|
Windows::UI::Xaml::Media::Brush BackgroundBrush();
|
||||||
|
|
||||||
// -------------------------------- WinRT Events ---------------------------------
|
// -------------------------------- WinRT Events ---------------------------------
|
||||||
// clang-format off
|
// clang-format off
|
||||||
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
|
WINRT_CALLBACK(FontSizeChanged, Control::FontSizeChangedEventArgs);
|
||||||
|
@ -127,8 +131,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
TYPED_EVENT(WarningBell, IInspectable, IInspectable);
|
TYPED_EVENT(WarningBell, IInspectable, IInspectable);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
WINRT_PROPERTY(IControlAppearance, UnfocusedAppearance);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct TermControlT<TermControl>; // friend our parent so it can bind private event handlers
|
friend struct TermControlT<TermControl>; // friend our parent so it can bind private event handlers
|
||||||
|
|
||||||
|
@ -146,7 +148,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
|
|
||||||
winrt::com_ptr<SearchBoxControl> _searchBox;
|
winrt::com_ptr<SearchBoxControl> _searchBox;
|
||||||
|
|
||||||
IControlSettings _settings;
|
|
||||||
bool _closing{ false };
|
bool _closing{ false };
|
||||||
bool _focused{ false };
|
bool _focused{ false };
|
||||||
bool _initializedTerminal{ false };
|
bool _initializedTerminal{ false };
|
||||||
|
@ -193,14 +194,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||||
return _closing;
|
return _closing;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _UpdateSettingsFromUIThread(IControlSettings newSettings);
|
void _UpdateSettingsFromUIThread();
|
||||||
void _UpdateAppearanceFromUIThread(IControlAppearance newAppearance);
|
void _UpdateAppearanceFromUIThread(Control::IControlAppearance newAppearance);
|
||||||
void _ApplyUISettings(const IControlSettings&);
|
void _ApplyUISettings();
|
||||||
|
winrt::fire_and_forget UpdateAppearance(Control::IControlAppearance newAppearance);
|
||||||
void _SetBackgroundImage(const IControlAppearance& newAppearance);
|
void _SetBackgroundImage(const IControlAppearance& newAppearance);
|
||||||
|
|
||||||
void _InitializeBackgroundBrush();
|
void _InitializeBackgroundBrush();
|
||||||
void _BackgroundColorChangedHandler(const IInspectable& sender, const IInspectable& args);
|
winrt::fire_and_forget _coreBackgroundColorChanged(const IInspectable& sender, const IInspectable& args);
|
||||||
winrt::fire_and_forget _changeBackgroundColor(const til::color bg);
|
void _changeBackgroundColor(const til::color bg);
|
||||||
|
void _changeBackgroundOpacity();
|
||||||
|
|
||||||
bool _InitializeTerminal();
|
bool _InitializeTerminal();
|
||||||
void _SetFontSize(int fontSize);
|
void _SetFontSize(int fontSize);
|
||||||
|
|
|
@ -17,14 +17,15 @@ namespace Microsoft.Terminal.Control
|
||||||
ICoreState
|
ICoreState
|
||||||
{
|
{
|
||||||
TermControl(IControlSettings settings,
|
TermControl(IControlSettings settings,
|
||||||
|
IControlAppearance unfocusedAppearance,
|
||||||
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||||
|
|
||||||
static Windows.Foundation.Size GetProposedDimensions(IControlSettings settings, UInt32 dpi);
|
static Windows.Foundation.Size GetProposedDimensions(IControlSettings settings, UInt32 dpi);
|
||||||
|
|
||||||
void UpdateSettings();
|
void UpdateControlSettings(IControlSettings settings);
|
||||||
|
void UpdateControlSettings(IControlSettings settings, IControlAppearance unfocusedAppearance);
|
||||||
|
|
||||||
Microsoft.Terminal.Control.IControlSettings Settings;
|
Microsoft.Terminal.Control.IControlSettings Settings { get; };
|
||||||
Microsoft.Terminal.Control.IControlAppearance UnfocusedAppearance;
|
|
||||||
|
|
||||||
event FontSizeChangedEventArgs FontSizeChanged;
|
event FontSizeChangedEventArgs FontSizeChanged;
|
||||||
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
||||||
|
@ -71,5 +72,7 @@ namespace Microsoft.Terminal.Control
|
||||||
void ToggleReadOnly();
|
void ToggleReadOnly();
|
||||||
|
|
||||||
String ReadEntireBuffer();
|
String ReadEntireBuffer();
|
||||||
|
|
||||||
|
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,37 @@ namespace Microsoft.Terminal.Core
|
||||||
UInt32 Value;
|
UInt32 Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Scheme
|
||||||
|
{
|
||||||
|
Microsoft.Terminal.Core.Color Foreground;
|
||||||
|
Microsoft.Terminal.Core.Color Background;
|
||||||
|
|
||||||
|
Microsoft.Terminal.Core.Color SelectionBackground;
|
||||||
|
|
||||||
|
Microsoft.Terminal.Core.Color CursorColor;
|
||||||
|
|
||||||
|
// Table: A WinRT struct doesn't allow pointers (READ: doesn't allow
|
||||||
|
// array members) in structs, but we very much would like this object to
|
||||||
|
// be a struct. So we'll call out each color individually. There's only
|
||||||
|
// 16, it's not that bad.
|
||||||
|
Microsoft.Terminal.Core.Color Black;
|
||||||
|
Microsoft.Terminal.Core.Color Red;
|
||||||
|
Microsoft.Terminal.Core.Color Green;
|
||||||
|
Microsoft.Terminal.Core.Color Yellow;
|
||||||
|
Microsoft.Terminal.Core.Color Blue;
|
||||||
|
Microsoft.Terminal.Core.Color Purple;
|
||||||
|
Microsoft.Terminal.Core.Color Cyan;
|
||||||
|
Microsoft.Terminal.Core.Color White;
|
||||||
|
Microsoft.Terminal.Core.Color BrightBlack;
|
||||||
|
Microsoft.Terminal.Core.Color BrightRed;
|
||||||
|
Microsoft.Terminal.Core.Color BrightGreen;
|
||||||
|
Microsoft.Terminal.Core.Color BrightYellow;
|
||||||
|
Microsoft.Terminal.Core.Color BrightBlue;
|
||||||
|
Microsoft.Terminal.Core.Color BrightPurple;
|
||||||
|
Microsoft.Terminal.Core.Color BrightCyan;
|
||||||
|
Microsoft.Terminal.Core.Color BrightWhite;
|
||||||
|
};
|
||||||
|
|
||||||
declare
|
declare
|
||||||
{
|
{
|
||||||
// Forward declare this parameterized specialization so that it lives
|
// Forward declare this parameterized specialization so that it lives
|
||||||
|
|
|
@ -178,13 +178,14 @@ void Terminal::UpdateSettings(ICoreSettings settings)
|
||||||
// - appearance: an ICoreAppearance with new settings values for us to use.
|
// - appearance: an ICoreAppearance with new settings values for us to use.
|
||||||
void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
|
void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
|
||||||
{
|
{
|
||||||
|
_intenseIsBright = appearance.IntenseIsBright();
|
||||||
|
_adjustIndistinguishableColors = appearance.AdjustIndistinguishableColors();
|
||||||
|
|
||||||
// Set the default background as transparent to prevent the
|
// Set the default background as transparent to prevent the
|
||||||
// DX layer from overwriting the background image or acrylic effect
|
// DX layer from overwriting the background image or acrylic effect
|
||||||
til::color newBackgroundColor{ appearance.DefaultBackground() };
|
til::color newBackgroundColor{ appearance.DefaultBackground() };
|
||||||
_defaultBg = newBackgroundColor.with_alpha(0);
|
_defaultBg = newBackgroundColor.with_alpha(0);
|
||||||
_defaultFg = appearance.DefaultForeground();
|
_defaultFg = appearance.DefaultForeground();
|
||||||
_intenseIsBright = appearance.IntenseIsBright();
|
|
||||||
_adjustIndistinguishableColors = appearance.AdjustIndistinguishableColors();
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
|
@ -1298,3 +1299,67 @@ const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarProgress() const noe
|
||||||
{
|
{
|
||||||
return _taskbarProgress;
|
return _taskbarProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scheme Terminal::GetColorScheme() const noexcept
|
||||||
|
{
|
||||||
|
Scheme s;
|
||||||
|
|
||||||
|
s.Foreground = til::color{ _defaultFg };
|
||||||
|
// Don't leak the implementation detail that our _defaultBg is stored
|
||||||
|
// internally without alpha.
|
||||||
|
s.Background = til::color{ _defaultBg.with_alpha(0xff) };
|
||||||
|
|
||||||
|
// SelectionBackground is stored in the ControlAppearance
|
||||||
|
s.CursorColor = til::color{ _buffer->GetCursor().GetColor() };
|
||||||
|
|
||||||
|
s.Black = til::color{ _colorTable[0] };
|
||||||
|
s.Red = til::color{ _colorTable[1] };
|
||||||
|
s.Green = til::color{ _colorTable[2] };
|
||||||
|
s.Yellow = til::color{ _colorTable[3] };
|
||||||
|
s.Blue = til::color{ _colorTable[4] };
|
||||||
|
s.Purple = til::color{ _colorTable[5] };
|
||||||
|
s.Cyan = til::color{ _colorTable[6] };
|
||||||
|
s.White = til::color{ _colorTable[7] };
|
||||||
|
s.BrightBlack = til::color{ _colorTable[8] };
|
||||||
|
s.BrightRed = til::color{ _colorTable[9] };
|
||||||
|
s.BrightGreen = til::color{ _colorTable[10] };
|
||||||
|
s.BrightYellow = til::color{ _colorTable[11] };
|
||||||
|
s.BrightBlue = til::color{ _colorTable[12] };
|
||||||
|
s.BrightPurple = til::color{ _colorTable[13] };
|
||||||
|
s.BrightCyan = til::color{ _colorTable[14] };
|
||||||
|
s.BrightWhite = til::color{ _colorTable[15] };
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Terminal::ApplyScheme(const Scheme& colorScheme)
|
||||||
|
{
|
||||||
|
_defaultFg = colorScheme.Foreground;
|
||||||
|
// Set the default background as transparent to prevent the
|
||||||
|
// DX layer from overwriting the background image or acrylic effect
|
||||||
|
til::color newBackgroundColor{ colorScheme.Background };
|
||||||
|
_defaultBg = newBackgroundColor.with_alpha(0);
|
||||||
|
|
||||||
|
_colorTable[0] = til::color{ colorScheme.Black };
|
||||||
|
_colorTable[1] = til::color{ colorScheme.Red };
|
||||||
|
_colorTable[2] = til::color{ colorScheme.Green };
|
||||||
|
_colorTable[3] = til::color{ colorScheme.Yellow };
|
||||||
|
_colorTable[4] = til::color{ colorScheme.Blue };
|
||||||
|
_colorTable[5] = til::color{ colorScheme.Purple };
|
||||||
|
_colorTable[6] = til::color{ colorScheme.Cyan };
|
||||||
|
_colorTable[7] = til::color{ colorScheme.White };
|
||||||
|
_colorTable[8] = til::color{ colorScheme.BrightBlack };
|
||||||
|
_colorTable[9] = til::color{ colorScheme.BrightRed };
|
||||||
|
_colorTable[10] = til::color{ colorScheme.BrightGreen };
|
||||||
|
_colorTable[11] = til::color{ colorScheme.BrightYellow };
|
||||||
|
_colorTable[12] = til::color{ colorScheme.BrightBlue };
|
||||||
|
_colorTable[13] = til::color{ colorScheme.BrightPurple };
|
||||||
|
_colorTable[14] = til::color{ colorScheme.BrightCyan };
|
||||||
|
_colorTable[15] = til::color{ colorScheme.BrightWhite };
|
||||||
|
|
||||||
|
_buffer->GetCursor().SetColor(til::color{ colorScheme.CursorColor });
|
||||||
|
|
||||||
|
if (_adjustIndistinguishableColors)
|
||||||
|
{
|
||||||
|
_MakeAdjustedColorArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace winrt::Microsoft::Terminal::Core
|
||||||
{
|
{
|
||||||
struct ICoreSettings;
|
struct ICoreSettings;
|
||||||
struct ICoreAppearance;
|
struct ICoreAppearance;
|
||||||
|
struct Scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Microsoft::Terminal::Core
|
namespace Microsoft::Terminal::Core
|
||||||
|
@ -214,6 +215,9 @@ public:
|
||||||
const std::optional<til::color> GetTabColor() const noexcept;
|
const std::optional<til::color> GetTabColor() const noexcept;
|
||||||
til::color GetDefaultBackground() const noexcept;
|
til::color GetDefaultBackground() const noexcept;
|
||||||
|
|
||||||
|
winrt::Microsoft::Terminal::Core::Scheme GetColorScheme() const noexcept;
|
||||||
|
void ApplyScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme);
|
||||||
|
|
||||||
Microsoft::Console::Render::BlinkingState& GetBlinkingState() const noexcept;
|
Microsoft::Console::Render::BlinkingState& GetBlinkingState() const noexcept;
|
||||||
|
|
||||||
const size_t GetTaskbarState() const noexcept;
|
const size_t GetTaskbarState() const noexcept;
|
||||||
|
|
|
@ -398,7 +398,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
Profiles::Profiles() :
|
Profiles::Profiles() :
|
||||||
_previewControl{ Control::TermControl(Model::TerminalSettings{}, make<PreviewConnection>()) }
|
_previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make<PreviewConnection>()) }
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
@ -453,26 +453,23 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||||
{
|
{
|
||||||
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentScrollState" });
|
_PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentScrollState" });
|
||||||
}
|
}
|
||||||
_previewControl.Settings(_State.Profile().TermSettings());
|
_previewControl.UpdateControlSettings(_State.Profile().TermSettings());
|
||||||
_previewControl.UpdateSettings();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// The Appearances object handles updating the values in the settings UI, but
|
// The Appearances object handles updating the values in the settings UI, but
|
||||||
// we still need to listen to the changes here just to update the preview control
|
// we still need to listen to the changes here just to update the preview control
|
||||||
_AppearanceViewModelChangedRevoker = _State.Profile().DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
|
_AppearanceViewModelChangedRevoker = _State.Profile().DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
|
||||||
_previewControl.Settings(_State.Profile().TermSettings());
|
_previewControl.UpdateControlSettings(_State.Profile().TermSettings());
|
||||||
_previewControl.UpdateSettings();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Navigate to the pivot in the provided navigation state
|
// Navigate to the pivot in the provided navigation state
|
||||||
ProfilesPivot().SelectedIndex(static_cast<int>(_State.LastActivePivot()));
|
ProfilesPivot().SelectedIndex(static_cast<int>(_State.LastActivePivot()));
|
||||||
|
|
||||||
_previewControl.Settings(_State.Profile().TermSettings());
|
|
||||||
// There is a possibility that the control has not fully initialized yet,
|
// There is a possibility that the control has not fully initialized yet,
|
||||||
// so wait for it to initialize before updating the settings (so we know
|
// so wait for it to initialize before updating the settings (so we know
|
||||||
// that the renderer is set up)
|
// that the renderer is set up)
|
||||||
_previewControl.Initialized([&](auto&& /*s*/, auto&& /*e*/) {
|
_previewControl.Initialized([&](auto&& /*s*/, auto&& /*e*/) {
|
||||||
_previewControl.UpdateSettings();
|
_previewControl.UpdateControlSettings(_State.Profile().TermSettings());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,3 +147,30 @@ void ColorScheme::SetColorTableEntry(uint8_t index, const Core::Color& value) no
|
||||||
THROW_HR_IF(E_INVALIDARG, index >= _table.size());
|
THROW_HR_IF(E_INVALIDARG, index >= _table.size());
|
||||||
_table[index] = value;
|
_table[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
winrt::Microsoft::Terminal::Core::Scheme ColorScheme::ToCoreScheme() const noexcept
|
||||||
|
{
|
||||||
|
winrt::Microsoft::Terminal::Core::Scheme coreScheme{};
|
||||||
|
|
||||||
|
coreScheme.Foreground = Foreground();
|
||||||
|
coreScheme.Background = Background();
|
||||||
|
coreScheme.CursorColor = CursorColor();
|
||||||
|
coreScheme.SelectionBackground = SelectionBackground();
|
||||||
|
coreScheme.Black = Table()[0];
|
||||||
|
coreScheme.Red = Table()[1];
|
||||||
|
coreScheme.Green = Table()[2];
|
||||||
|
coreScheme.Yellow = Table()[3];
|
||||||
|
coreScheme.Blue = Table()[4];
|
||||||
|
coreScheme.Purple = Table()[5];
|
||||||
|
coreScheme.Cyan = Table()[6];
|
||||||
|
coreScheme.White = Table()[7];
|
||||||
|
coreScheme.BrightBlack = Table()[8];
|
||||||
|
coreScheme.BrightRed = Table()[9];
|
||||||
|
coreScheme.BrightGreen = Table()[10];
|
||||||
|
coreScheme.BrightYellow = Table()[11];
|
||||||
|
coreScheme.BrightBlue = Table()[12];
|
||||||
|
coreScheme.BrightPurple = Table()[13];
|
||||||
|
coreScheme.BrightCyan = Table()[14];
|
||||||
|
coreScheme.BrightWhite = Table()[15];
|
||||||
|
return coreScheme;
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
static com_ptr<ColorScheme> FromJson(const Json::Value& json);
|
static com_ptr<ColorScheme> FromJson(const Json::Value& json);
|
||||||
Json::Value ToJson() const;
|
Json::Value ToJson() const;
|
||||||
|
|
||||||
|
winrt::Microsoft::Terminal::Core::Scheme ToCoreScheme() const noexcept;
|
||||||
|
|
||||||
com_array<Core::Color> Table() const noexcept;
|
com_array<Core::Color> Table() const noexcept;
|
||||||
void SetColorTableEntry(uint8_t index, const Core::Color& value) noexcept;
|
void SetColorTableEntry(uint8_t index, const Core::Color& value) noexcept;
|
||||||
|
|
||||||
|
|
|
@ -19,5 +19,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||||
// we expose the getter as a function.
|
// we expose the getter as a function.
|
||||||
Microsoft.Terminal.Core.Color[] Table();
|
Microsoft.Terminal.Core.Color[] Table();
|
||||||
void SetColorTableEntry(UInt8 index, Microsoft.Terminal.Core.Color value);
|
void SetColorTableEntry(UInt8 index, Microsoft.Terminal.Core.Color value);
|
||||||
|
|
||||||
|
Microsoft.Terminal.Core.Scheme ToCoreScheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,59 +206,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
_Opacity = appearance.Opacity();
|
_Opacity = appearance.Opacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
|
||||||
// - Creates a TerminalSettingsCreateResult from a parent TerminalSettingsCreateResult
|
|
||||||
// - The returned defaultSettings inherits from the parent's defaultSettings, and the
|
|
||||||
// returned unfocusedSettings inherits from the returned defaultSettings
|
|
||||||
// - Note that the unfocused settings needs to be entirely unchanged _except_ we need to
|
|
||||||
// set its parent to the other settings object that we return. This is because the overrides
|
|
||||||
// made by the control will live in that other settings object, so we want to make
|
|
||||||
// sure the unfocused settings inherit from that.
|
|
||||||
// - Another way to think about this is that initially we have UnfocusedSettings inherit
|
|
||||||
// from DefaultSettings. This function simply adds another TerminalSettings object
|
|
||||||
// in the middle of these two, so UnfocusedSettings now inherits from the new object
|
|
||||||
// and the new object inherits from the DefaultSettings. And this new object is what
|
|
||||||
// the control can put overrides in.
|
|
||||||
// Arguments:
|
|
||||||
// - parent: the TerminalSettingsCreateResult that we create a new one from
|
|
||||||
// Return Value:
|
|
||||||
// - A TerminalSettingsCreateResult object that contains a defaultSettings that inherits
|
|
||||||
// from parent's defaultSettings, and contains an unfocusedSettings that inherits from
|
|
||||||
// its defaultSettings
|
|
||||||
Model::TerminalSettingsCreateResult TerminalSettings::CreateWithParent(const Model::TerminalSettingsCreateResult& parent)
|
|
||||||
{
|
|
||||||
THROW_HR_IF_NULL(E_INVALIDARG, parent);
|
|
||||||
|
|
||||||
auto defaultImpl{ get_self<TerminalSettings>(parent.DefaultSettings()) };
|
|
||||||
auto defaultChild = defaultImpl->CreateChild();
|
|
||||||
if (parent.UnfocusedSettings())
|
|
||||||
{
|
|
||||||
parent.UnfocusedSettings().SetParent(*defaultChild);
|
|
||||||
}
|
|
||||||
return winrt::make<TerminalSettingsCreateResult>(*defaultChild, parent.UnfocusedSettings());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method Description:
|
|
||||||
// - Sets our parent to the provided TerminalSettings
|
|
||||||
// Arguments:
|
|
||||||
// - parent: our new parent
|
|
||||||
void TerminalSettings::SetParent(const Model::TerminalSettings& parent)
|
|
||||||
{
|
|
||||||
ClearParents();
|
|
||||||
com_ptr<TerminalSettings> parentImpl;
|
|
||||||
parentImpl.copy_from(get_self<TerminalSettings>(parent));
|
|
||||||
InsertParent(parentImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
Model::TerminalSettings TerminalSettings::GetParent()
|
|
||||||
{
|
|
||||||
if (_parents.size() > 0)
|
|
||||||
{
|
|
||||||
return *_parents.at(0);
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Apply Profile settings, as well as any colors from our color scheme, if we have one.
|
// - Apply Profile settings, as well as any colors from our color scheme, if we have one.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
|
|
@ -64,12 +64,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
const Model::NewTerminalArgs& newTerminalArgs,
|
const Model::NewTerminalArgs& newTerminalArgs,
|
||||||
const Control::IKeyBindings& keybindings);
|
const Control::IKeyBindings& keybindings);
|
||||||
|
|
||||||
static Model::TerminalSettingsCreateResult CreateWithParent(const Model::TerminalSettingsCreateResult& parent);
|
|
||||||
|
|
||||||
Model::TerminalSettings GetParent();
|
|
||||||
|
|
||||||
void SetParent(const Model::TerminalSettings& parent);
|
|
||||||
|
|
||||||
void ApplyColorScheme(const Model::ColorScheme& scheme);
|
void ApplyColorScheme(const Model::ColorScheme& scheme);
|
||||||
|
|
||||||
// --------------------------- Core Settings ---------------------------
|
// --------------------------- Core Settings ---------------------------
|
||||||
|
@ -95,7 +89,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||||
INHERITABLE_SETTING(Model::TerminalSettings, uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
|
INHERITABLE_SETTING(Model::TerminalSettings, uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
|
||||||
INHERITABLE_SETTING(Model::TerminalSettings, hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
|
INHERITABLE_SETTING(Model::TerminalSettings, hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
|
||||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, CopyOnSelect, false);
|
INHERITABLE_SETTING(Model::TerminalSettings, bool, CopyOnSelect, false);
|
||||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, InputServiceWarning, true);
|
|
||||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, FocusFollowMouse, false);
|
INHERITABLE_SETTING(Model::TerminalSettings, bool, FocusFollowMouse, false);
|
||||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, TrimBlockSelection, false);
|
INHERITABLE_SETTING(Model::TerminalSettings, bool, TrimBlockSelection, false);
|
||||||
INHERITABLE_SETTING(Model::TerminalSettings, bool, DetectURLs, true);
|
INHERITABLE_SETTING(Model::TerminalSettings, bool, DetectURLs, true);
|
||||||
|
|
|
@ -28,12 +28,16 @@ namespace Microsoft.Terminal.Settings.Model
|
||||||
|
|
||||||
static TerminalSettingsCreateResult CreateWithProfile(CascadiaSettings appSettings, Profile profile, Microsoft.Terminal.Control.IKeyBindings keybindings);
|
static TerminalSettingsCreateResult CreateWithProfile(CascadiaSettings appSettings, Profile profile, Microsoft.Terminal.Control.IKeyBindings keybindings);
|
||||||
static TerminalSettingsCreateResult CreateWithNewTerminalArgs(CascadiaSettings appSettings, NewTerminalArgs newTerminalArgs, Microsoft.Terminal.Control.IKeyBindings keybindings);
|
static TerminalSettingsCreateResult CreateWithNewTerminalArgs(CascadiaSettings appSettings, NewTerminalArgs newTerminalArgs, Microsoft.Terminal.Control.IKeyBindings keybindings);
|
||||||
static TerminalSettingsCreateResult CreateWithParent(TerminalSettingsCreateResult parent);
|
|
||||||
|
|
||||||
void SetParent(TerminalSettings parent);
|
|
||||||
TerminalSettings GetParent();
|
|
||||||
void ApplyColorScheme(ColorScheme scheme);
|
void ApplyColorScheme(ColorScheme scheme);
|
||||||
|
|
||||||
ColorScheme AppliedColorScheme;
|
ColorScheme AppliedColorScheme;
|
||||||
|
|
||||||
|
// The getters for these are already defined in IControlSettings. So
|
||||||
|
// we're just adding the setters here, because TerminalApp likes to be
|
||||||
|
// able to change these at runtime (e.g. when duplicating a pane).
|
||||||
|
String Commandline { set; };
|
||||||
|
String StartingDirectory { set; };
|
||||||
|
String EnvironmentVariables { set; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace ControlUnitTests
|
||||||
{
|
{
|
||||||
Log::Comment(L"Create ControlCore object");
|
Log::Comment(L"Create ControlCore object");
|
||||||
|
|
||||||
auto core = winrt::make_self<Control::implementation::ControlCore>(settings, conn);
|
auto core = winrt::make_self<Control::implementation::ControlCore>(settings, settings, conn);
|
||||||
core->_inUnitTests = true;
|
core->_inUnitTests = true;
|
||||||
return core;
|
return core;
|
||||||
}
|
}
|
||||||
|
@ -128,13 +128,14 @@ namespace ControlUnitTests
|
||||||
double expectedOpacity = 0.5;
|
double expectedOpacity = 0.5;
|
||||||
auto opacityCallback = [&](auto&&, Control::TransparencyChangedEventArgs args) mutable {
|
auto opacityCallback = [&](auto&&, Control::TransparencyChangedEventArgs args) mutable {
|
||||||
VERIFY_ARE_EQUAL(expectedOpacity, args.Opacity());
|
VERIFY_ARE_EQUAL(expectedOpacity, args.Opacity());
|
||||||
VERIFY_ARE_EQUAL(expectedOpacity, settings->Opacity());
|
VERIFY_ARE_EQUAL(expectedOpacity, core->Opacity());
|
||||||
VERIFY_ARE_EQUAL(expectedOpacity, core->_settings.Opacity());
|
// The Settings object's opacity shouldn't be changed
|
||||||
|
VERIFY_ARE_EQUAL(0.5, settings->Opacity());
|
||||||
|
|
||||||
if (expectedOpacity < 1.0)
|
if (expectedOpacity < 1.0)
|
||||||
{
|
{
|
||||||
VERIFY_IS_TRUE(settings->UseAcrylic());
|
VERIFY_IS_TRUE(settings->UseAcrylic());
|
||||||
VERIFY_IS_TRUE(core->_settings.UseAcrylic());
|
VERIFY_IS_TRUE(core->_settings->UseAcrylic());
|
||||||
}
|
}
|
||||||
|
|
||||||
// GH#603: Adjusting opacity shouldn't change whether or not we
|
// GH#603: Adjusting opacity shouldn't change whether or not we
|
||||||
|
@ -142,8 +143,8 @@ namespace ControlUnitTests
|
||||||
|
|
||||||
auto expectedUseAcrylic = winrt::Microsoft::Terminal::Control::implementation::ControlCore::IsVintageOpacityAvailable() ? true :
|
auto expectedUseAcrylic = winrt::Microsoft::Terminal::Control::implementation::ControlCore::IsVintageOpacityAvailable() ? true :
|
||||||
(expectedOpacity < 1.0 ? true : false);
|
(expectedOpacity < 1.0 ? true : false);
|
||||||
VERIFY_ARE_EQUAL(expectedUseAcrylic, settings->UseAcrylic());
|
VERIFY_ARE_EQUAL(expectedUseAcrylic, core->UseAcrylic());
|
||||||
VERIFY_ARE_EQUAL(expectedUseAcrylic, core->_settings.UseAcrylic());
|
VERIFY_ARE_EQUAL(true, core->_settings->UseAcrylic());
|
||||||
};
|
};
|
||||||
core->TransparencyChanged(opacityCallback);
|
core->TransparencyChanged(opacityCallback);
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace ControlUnitTests
|
||||||
TerminalConnection::ITerminalConnection conn)
|
TerminalConnection::ITerminalConnection conn)
|
||||||
{
|
{
|
||||||
Log::Comment(L"Create ControlInteractivity object");
|
Log::Comment(L"Create ControlInteractivity object");
|
||||||
auto interactivity = winrt::make_self<Control::implementation::ControlInteractivity>(settings, conn);
|
auto interactivity = winrt::make_self<Control::implementation::ControlInteractivity>(settings, settings, conn);
|
||||||
VERIFY_IS_NOT_NULL(interactivity);
|
VERIFY_IS_NOT_NULL(interactivity);
|
||||||
auto core = interactivity->_core;
|
auto core = interactivity->_core;
|
||||||
core->_inUnitTests = true;
|
core->_inUnitTests = true;
|
||||||
|
@ -116,13 +116,14 @@ namespace ControlUnitTests
|
||||||
double expectedOpacity = 0.5;
|
double expectedOpacity = 0.5;
|
||||||
auto opacityCallback = [&](auto&&, Control::TransparencyChangedEventArgs args) mutable {
|
auto opacityCallback = [&](auto&&, Control::TransparencyChangedEventArgs args) mutable {
|
||||||
VERIFY_ARE_EQUAL(expectedOpacity, args.Opacity());
|
VERIFY_ARE_EQUAL(expectedOpacity, args.Opacity());
|
||||||
VERIFY_ARE_EQUAL(expectedOpacity, settings->Opacity());
|
VERIFY_ARE_EQUAL(expectedOpacity, core->Opacity());
|
||||||
VERIFY_ARE_EQUAL(expectedOpacity, core->_settings.Opacity());
|
// The Settings object's opacity shouldn't be changed
|
||||||
|
VERIFY_ARE_EQUAL(0.5, settings->Opacity());
|
||||||
|
|
||||||
auto expectedUseAcrylic = winrt::Microsoft::Terminal::Control::implementation::ControlCore::IsVintageOpacityAvailable() ? useAcrylic :
|
auto expectedUseAcrylic = winrt::Microsoft::Terminal::Control::implementation::ControlCore::IsVintageOpacityAvailable() ? useAcrylic :
|
||||||
(expectedOpacity < 1.0 ? true : false);
|
(expectedOpacity < 1.0 ? true : false);
|
||||||
VERIFY_ARE_EQUAL(expectedUseAcrylic, settings->UseAcrylic());
|
VERIFY_ARE_EQUAL(useAcrylic, settings->UseAcrylic());
|
||||||
VERIFY_ARE_EQUAL(expectedUseAcrylic, core->_settings.UseAcrylic());
|
VERIFY_ARE_EQUAL(expectedUseAcrylic, core->UseAcrylic());
|
||||||
};
|
};
|
||||||
core->TransparencyChanged(opacityCallback);
|
core->TransparencyChanged(opacityCallback);
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ namespace ControlUnitTests
|
||||||
WINRT_PROPERTY(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
|
WINRT_PROPERTY(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT);
|
||||||
WINRT_PROPERTY(winrt::hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
|
WINRT_PROPERTY(winrt::hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS);
|
||||||
WINRT_PROPERTY(bool, CopyOnSelect, false);
|
WINRT_PROPERTY(bool, CopyOnSelect, false);
|
||||||
WINRT_PROPERTY(bool, InputServiceWarning, true);
|
|
||||||
WINRT_PROPERTY(bool, FocusFollowMouse, false);
|
WINRT_PROPERTY(bool, FocusFollowMouse, false);
|
||||||
|
|
||||||
WINRT_PROPERTY(winrt::Windows::Foundation::IReference<winrt::Microsoft::Terminal::Core::Color>, TabColor, nullptr);
|
WINRT_PROPERTY(winrt::Windows::Foundation::IReference<winrt::Microsoft::Terminal::Core::Color>, TabColor, nullptr);
|
||||||
|
|
|
@ -87,51 +87,203 @@ void NonClientIslandWindow::MakeWindow() noexcept
|
||||||
THROW_HR_IF_NULL(E_UNEXPECTED, _dragBarWindow);
|
THROW_HR_IF_NULL(E_UNEXPECTED, _dragBarWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function Description:
|
LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer)
|
||||||
// - The window procedure for the drag bar forwards clicks on its client area to its parent as non-client clicks.
|
|
||||||
LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
|
|
||||||
{
|
{
|
||||||
std::optional<UINT> nonClientMessage{ std::nullopt };
|
RECT rcParent = GetWindowRect();
|
||||||
|
// The size of the buttons doesn't change over the life of the application.
|
||||||
|
const auto buttonWidthInDips{ _titlebar.CaptionButtonWidth() };
|
||||||
|
|
||||||
// translate WM_ messages on the window to WM_NC* on the top level window
|
// However, the DPI scaling might, so get the updated size of the buttons in pixels
|
||||||
|
const auto buttonWidthInPixels{ buttonWidthInDips * GetCurrentDpiScale() };
|
||||||
|
|
||||||
|
// make sure to account for the width of the window frame!
|
||||||
|
const til::rectangle nonClientFrame{ GetNonClientFrame(_currentDpi) };
|
||||||
|
const auto rightBorder{ rcParent.right - nonClientFrame.right<int>() };
|
||||||
|
// From the right to the left,
|
||||||
|
// * are we in the close button?
|
||||||
|
// * the maximize button?
|
||||||
|
// * the minimize button?
|
||||||
|
// If we're not, then we're in either the top resize border, or just
|
||||||
|
// generally in the titlebar.
|
||||||
|
if ((rightBorder - pointer.x()) < (buttonWidthInPixels))
|
||||||
|
{
|
||||||
|
return HTCLOSE;
|
||||||
|
}
|
||||||
|
else if ((rightBorder - pointer.x()) < (buttonWidthInPixels * 2))
|
||||||
|
{
|
||||||
|
return HTMAXBUTTON;
|
||||||
|
}
|
||||||
|
else if ((rightBorder - pointer.x()) < (buttonWidthInPixels * 3))
|
||||||
|
{
|
||||||
|
return HTMINBUTTON;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If we're not on a caption button, then check if we're on the top
|
||||||
|
// border. If we're not on the top border, then we're just generally in
|
||||||
|
// the caption area.
|
||||||
|
const auto resizeBorderHeight = _GetResizeHandleHeight();
|
||||||
|
const auto isOnResizeBorder = pointer.y() < rcParent.top + resizeBorderHeight;
|
||||||
|
|
||||||
|
return isOnResizeBorder ? HTTOP : HTCAPTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function Description:
|
||||||
|
// - The window procedure for the drag bar forwards clicks on its client area to
|
||||||
|
// its parent as non-client clicks.
|
||||||
|
// - BODGY: It also _manually_ handles the caption buttons. They exist in the
|
||||||
|
// titlebar, and work reasonably well with just XAML, if the drag bar isn't
|
||||||
|
// covering them.
|
||||||
|
// - However, to get snap layout support (GH#9443), we need to actually return
|
||||||
|
// HTMAXBUTTON where the maximize button is. If the drag bar doesn't cover the
|
||||||
|
// caption buttons, then the core input site (which takes up the entirety of
|
||||||
|
// the XAML island) will steal the WM_NCHITTEST before we get a chance to
|
||||||
|
// handle it.
|
||||||
|
// - So, the drag bar covers the caption buttons, and manually handles hovering
|
||||||
|
// and pressing them when needed. This gives the impression that they're
|
||||||
|
// getting input as they normally would, even if they're not _really_ getting
|
||||||
|
// input via XAML.
|
||||||
|
LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message,
|
||||||
|
WPARAM const wparam,
|
||||||
|
LPARAM const lparam) noexcept
|
||||||
|
{
|
||||||
switch (message)
|
switch (message)
|
||||||
{
|
{
|
||||||
case WM_LBUTTONDOWN:
|
case WM_NCHITTEST:
|
||||||
nonClientMessage = WM_NCLBUTTONDOWN;
|
{
|
||||||
break;
|
// Try to determine what part of the window is being hovered here. This
|
||||||
case WM_LBUTTONDBLCLK:
|
// is absolutely critical to making sure Snap Layouts (GH#9443) works!
|
||||||
nonClientMessage = WM_NCLBUTTONDBLCLK;
|
return _dragBarNcHitTest(til::point{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) });
|
||||||
break;
|
|
||||||
case WM_LBUTTONUP:
|
|
||||||
nonClientMessage = WM_NCLBUTTONUP;
|
|
||||||
break;
|
|
||||||
case WM_RBUTTONDOWN:
|
|
||||||
nonClientMessage = WM_NCRBUTTONDOWN;
|
|
||||||
break;
|
|
||||||
case WM_RBUTTONDBLCLK:
|
|
||||||
nonClientMessage = WM_NCRBUTTONDBLCLK;
|
|
||||||
break;
|
|
||||||
case WM_RBUTTONUP:
|
|
||||||
nonClientMessage = WM_NCRBUTTONUP;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (nonClientMessage.has_value())
|
case WM_NCMOUSEMOVE:
|
||||||
|
// When we get this message, it's because the mouse moved when it was
|
||||||
|
// over somewhere we said was the non-client area.
|
||||||
|
//
|
||||||
|
// We'll use this to communicate state to the title bar control, so that
|
||||||
|
// it can update its visuals.
|
||||||
|
// - If we're over a button, hover it.
|
||||||
|
// - If we're over _anything else_, stop hovering the buttons.
|
||||||
|
switch (wparam)
|
||||||
{
|
{
|
||||||
const POINT clientPt{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
|
case HTTOP:
|
||||||
POINT screenPt{ clientPt };
|
case HTCAPTION:
|
||||||
if (ClientToScreen(_dragBarWindow.get(), &screenPt))
|
|
||||||
{
|
{
|
||||||
|
_titlebar.ReleaseButtons();
|
||||||
|
|
||||||
|
// Pass caption-related nonclient messages to the parent window.
|
||||||
|
// Make sure to do this for the HTTOP, which is the top resize
|
||||||
|
// border, so we can resize the window on the top.
|
||||||
auto parentWindow{ GetHandle() };
|
auto parentWindow{ GetHandle() };
|
||||||
|
return SendMessage(parentWindow, message, wparam, lparam);
|
||||||
const LPARAM newLparam = MAKELPARAM(screenPt.x, screenPt.y);
|
|
||||||
// Hit test the parent window at the screen coordinates the user clicked in the drag input sink window,
|
|
||||||
// then pass that click through as an NC click in that location.
|
|
||||||
const LRESULT hitTest{ SendMessage(parentWindow, WM_NCHITTEST, 0, newLparam) };
|
|
||||||
SendMessage(parentWindow, nonClientMessage.value(), hitTest, newLparam);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
case HTMINBUTTON:
|
||||||
|
case HTMAXBUTTON:
|
||||||
|
case HTCLOSE:
|
||||||
|
_titlebar.HoverButton(static_cast<winrt::TerminalApp::CaptionButton>(wparam));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_titlebar.ReleaseButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven't previously asked for mouse tracking, request mouse
|
||||||
|
// tracking. We need to do this so we can get the WM_NCMOUSELEAVE
|
||||||
|
// message when the mouse leave the titlebar. Otherwise, we won't always
|
||||||
|
// get that message (especially if the user moves the mouse _real
|
||||||
|
// fast_).
|
||||||
|
if (!_trackingMouse &&
|
||||||
|
(wparam == HTMINBUTTON || wparam == HTMAXBUTTON || wparam == HTCLOSE))
|
||||||
|
{
|
||||||
|
TRACKMOUSEEVENT ev{};
|
||||||
|
ev.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||||
|
// TME_NONCLIENT is absolutely critical here. In my experimentation,
|
||||||
|
// we'd get WM_MOUSELEAVE messages after just a HOVER_DEFAULT
|
||||||
|
// timeout even though we're not requesting TME_HOVER, which kinda
|
||||||
|
// ruined the whole point of this.
|
||||||
|
ev.dwFlags = TME_LEAVE | TME_NONCLIENT;
|
||||||
|
ev.hwndTrack = _dragBarWindow.get();
|
||||||
|
ev.dwHoverTime = HOVER_DEFAULT; // we don't _really_ care about this.
|
||||||
|
LOG_IF_WIN32_BOOL_FALSE(TrackMouseEvent(&ev));
|
||||||
|
_trackingMouse = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_NCMOUSELEAVE:
|
||||||
|
case WM_MOUSELEAVE:
|
||||||
|
// When the mouse leaves the drag rect, make sure to dismiss any hover.
|
||||||
|
_titlebar.ReleaseButtons();
|
||||||
|
_trackingMouse = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// NB: *Shouldn't be forwarding these* when they're not over the caption
|
||||||
|
// because they can inadvertently take action using the system's default
|
||||||
|
// metrics instead of our own.
|
||||||
|
case WM_NCLBUTTONDOWN:
|
||||||
|
case WM_NCLBUTTONDBLCLK:
|
||||||
|
// Manual handling for mouse clicks in the drag bar. If it's in a
|
||||||
|
// caption button, then tell the titlebar to "press" the button, which
|
||||||
|
// should change its visual state.
|
||||||
|
//
|
||||||
|
// If it's not in a caption button, then just forward the message along
|
||||||
|
// to the root HWND. Make sure to do this for the HTTOP, which is the
|
||||||
|
// top resize border.
|
||||||
|
switch (wparam)
|
||||||
|
{
|
||||||
|
case HTTOP:
|
||||||
|
case HTCAPTION:
|
||||||
|
{
|
||||||
|
// Pass caption-related nonclient messages to the parent window.
|
||||||
|
auto parentWindow{ GetHandle() };
|
||||||
|
return SendMessage(parentWindow, message, wparam, lparam);
|
||||||
|
}
|
||||||
|
// The buttons won't work as you'd expect; we need to handle those
|
||||||
|
// ourselves.
|
||||||
|
case HTMINBUTTON:
|
||||||
|
case HTMAXBUTTON:
|
||||||
|
case HTCLOSE:
|
||||||
|
_titlebar.PressButton(static_cast<winrt::TerminalApp::CaptionButton>(wparam));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_NCLBUTTONUP:
|
||||||
|
// Manual handling for mouse RELEASES in the drag bar. If it's in a
|
||||||
|
// caption button, then manually handle what we'd expect for that button.
|
||||||
|
//
|
||||||
|
// If it's not in a caption button, then just forward the message along
|
||||||
|
// to the root HWND.
|
||||||
|
switch (wparam)
|
||||||
|
{
|
||||||
|
case HTTOP:
|
||||||
|
case HTCAPTION:
|
||||||
|
{
|
||||||
|
// Pass caption-related nonclient messages to the parent window.
|
||||||
|
// The buttons won't work as you'd expect; we need to handle those ourselves.
|
||||||
|
auto parentWindow{ GetHandle() };
|
||||||
|
return SendMessage(parentWindow, message, wparam, lparam);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// If we do find a button, then tell the titlebar to raise the same
|
||||||
|
// event that would be raised if it were "tapped"
|
||||||
|
case HTMINBUTTON:
|
||||||
|
case HTMAXBUTTON:
|
||||||
|
case HTCLOSE:
|
||||||
|
_titlebar.ReleaseButtons();
|
||||||
|
_titlebar.ClickButton(static_cast<winrt::TerminalApp::CaptionButton>(wparam));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Make sure to pass along right-clicks in this region to our parent window
|
||||||
|
// - we don't need to handle these.
|
||||||
|
case WM_NCRBUTTONDOWN:
|
||||||
|
case WM_NCRBUTTONDBLCLK:
|
||||||
|
case WM_NCRBUTTONUP:
|
||||||
|
auto parentWindow{ GetHandle() };
|
||||||
|
return SendMessage(parentWindow, message, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProc(_dragBarWindow.get(), message, wparam, lparam);
|
return DefWindowProc(_dragBarWindow.get(), message, wparam, lparam);
|
||||||
|
@ -279,10 +431,17 @@ RECT NonClientIslandWindow::_GetDragAreaRect() const noexcept
|
||||||
{
|
{
|
||||||
const auto scale = GetCurrentDpiScale();
|
const auto scale = GetCurrentDpiScale();
|
||||||
const auto transform = _dragBar.TransformToVisual(_rootGrid);
|
const auto transform = _dragBar.TransformToVisual(_rootGrid);
|
||||||
|
|
||||||
|
// GH#9443: Previously, we'd only extend the drag bar from the left of
|
||||||
|
// the tabs to the right of the caption buttons. Now, we're extending it
|
||||||
|
// all the way to the right side of the window, covering the caption
|
||||||
|
// buttons. We'll manually handle input to those buttons, to make it
|
||||||
|
// seem like they're still getting XAML input. We do this so we can get
|
||||||
|
// snap layout support for the maximize button.
|
||||||
const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{
|
const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{
|
||||||
0.0f,
|
0.0f,
|
||||||
0.0f,
|
0.0f,
|
||||||
static_cast<float>(_dragBar.ActualWidth()),
|
static_cast<float>(_rootGrid.ActualWidth()),
|
||||||
static_cast<float>(_dragBar.ActualHeight())
|
static_cast<float>(_dragBar.ActualHeight())
|
||||||
};
|
};
|
||||||
const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect);
|
const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect);
|
||||||
|
@ -550,6 +709,7 @@ int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept
|
||||||
// we didn't change them.
|
// we didn't change them.
|
||||||
LPARAM lParam = MAKELONG(ptMouse.x, ptMouse.y);
|
LPARAM lParam = MAKELONG(ptMouse.x, ptMouse.y);
|
||||||
const auto originalRet = DefWindowProc(_window.get(), WM_NCHITTEST, 0, lParam);
|
const auto originalRet = DefWindowProc(_window.get(), WM_NCHITTEST, 0, lParam);
|
||||||
|
|
||||||
if (originalRet != HTCLIENT)
|
if (originalRet != HTCLIENT)
|
||||||
{
|
{
|
||||||
// If we're the quake window, suppress resizing on any side except the
|
// If we're the quake window, suppress resizing on any side except the
|
||||||
|
|
|
@ -62,6 +62,7 @@ private:
|
||||||
winrt::Windows::UI::Xaml::ElementTheme _theme;
|
winrt::Windows::UI::Xaml::ElementTheme _theme;
|
||||||
|
|
||||||
bool _isMaximized;
|
bool _isMaximized;
|
||||||
|
bool _trackingMouse{ false };
|
||||||
|
|
||||||
[[nodiscard]] static LRESULT __stdcall _StaticInputSinkWndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept;
|
[[nodiscard]] static LRESULT __stdcall _StaticInputSinkWndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept;
|
||||||
[[nodiscard]] LRESULT _InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept;
|
[[nodiscard]] LRESULT _InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept;
|
||||||
|
@ -71,6 +72,7 @@ private:
|
||||||
int _GetResizeHandleHeight() const noexcept;
|
int _GetResizeHandleHeight() const noexcept;
|
||||||
RECT _GetDragAreaRect() const noexcept;
|
RECT _GetDragAreaRect() const noexcept;
|
||||||
int _GetTopBorderHeight() const noexcept;
|
int _GetTopBorderHeight() const noexcept;
|
||||||
|
LRESULT _dragBarNcHitTest(const til::point& pointer);
|
||||||
|
|
||||||
[[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override;
|
[[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override;
|
||||||
[[nodiscard]] LRESULT _OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept;
|
[[nodiscard]] LRESULT _OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept;
|
||||||
|
|
70
src/cascadia/inc/ControlProperties.h
Normal file
70
src/cascadia/inc/ControlProperties.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// --------------------------- Core Appearance ---------------------------
|
||||||
|
// All of these settings are defined in ICoreAppearance.
|
||||||
|
#define CORE_APPEARANCE_SETTINGS(X) \
|
||||||
|
X(til::color, DefaultForeground, DEFAULT_FOREGROUND) \
|
||||||
|
X(til::color, DefaultBackground, DEFAULT_BACKGROUND) \
|
||||||
|
X(til::color, CursorColor, DEFAULT_CURSOR_COLOR) \
|
||||||
|
X(winrt::Microsoft::Terminal::Core::CursorStyle, CursorShape, winrt::Microsoft::Terminal::Core::CursorStyle::Vintage) \
|
||||||
|
X(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT) \
|
||||||
|
X(bool, IntenseIsBright, true) \
|
||||||
|
X(bool, AdjustIndistinguishableColors, true)
|
||||||
|
|
||||||
|
// --------------------------- Control Appearance ---------------------------
|
||||||
|
// All of these settings are defined in IControlSettings.
|
||||||
|
#define CONTROL_APPEARANCE_SETTINGS(X) \
|
||||||
|
X(til::color, SelectionBackground, DEFAULT_FOREGROUND) \
|
||||||
|
X(double, Opacity, 1.0) \
|
||||||
|
X(winrt::hstring, BackgroundImage) \
|
||||||
|
X(double, BackgroundImageOpacity, 1.0) \
|
||||||
|
X(winrt::Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill) \
|
||||||
|
X(winrt::Windows::UI::Xaml::HorizontalAlignment, BackgroundImageHorizontalAlignment, winrt::Windows::UI::Xaml::HorizontalAlignment::Center) \
|
||||||
|
X(winrt::Windows::UI::Xaml::VerticalAlignment, BackgroundImageVerticalAlignment, winrt::Windows::UI::Xaml::VerticalAlignment::Center) \
|
||||||
|
X(bool, IntenseIsBold) \
|
||||||
|
X(bool, RetroTerminalEffect, false) \
|
||||||
|
X(winrt::hstring, PixelShaderPath)
|
||||||
|
|
||||||
|
// --------------------------- Core Settings ---------------------------
|
||||||
|
// All of these settings are defined in ICoreSettings.
|
||||||
|
#define CORE_SETTINGS(X) \
|
||||||
|
X(int32_t, HistorySize, DEFAULT_HISTORY_SIZE) \
|
||||||
|
X(int32_t, InitialRows, 30) \
|
||||||
|
X(int32_t, InitialCols, 80) \
|
||||||
|
X(bool, SnapOnInput, true) \
|
||||||
|
X(bool, AltGrAliasing, true) \
|
||||||
|
X(winrt::hstring, WordDelimiters, DEFAULT_WORD_DELIMITERS) \
|
||||||
|
X(bool, CopyOnSelect, false) \
|
||||||
|
X(bool, FocusFollowMouse, false) \
|
||||||
|
X(winrt::Windows::Foundation::IReference<winrt::Microsoft::Terminal::Core::Color>, TabColor, nullptr) \
|
||||||
|
X(winrt::Windows::Foundation::IReference<winrt::Microsoft::Terminal::Core::Color>, StartingTabColor, nullptr) \
|
||||||
|
X(bool, TrimBlockSelection, false) \
|
||||||
|
X(bool, DetectURLs, true)
|
||||||
|
|
||||||
|
// --------------------------- Control Settings ---------------------------
|
||||||
|
// All of these settings are defined in IControlSettings.
|
||||||
|
#define CONTROL_SETTINGS(X) \
|
||||||
|
X(winrt::hstring, ProfileName) \
|
||||||
|
X(winrt::hstring, ProfileSource) \
|
||||||
|
X(bool, UseAcrylic, false) \
|
||||||
|
X(winrt::hstring, Padding, DEFAULT_PADDING) \
|
||||||
|
X(winrt::hstring, FontFace, L"Consolas") \
|
||||||
|
X(int32_t, FontSize, DEFAULT_FONT_SIZE) \
|
||||||
|
X(winrt::Windows::UI::Text::FontWeight, FontWeight) \
|
||||||
|
X(IFontFeatureMap, FontFeatures) \
|
||||||
|
X(IFontAxesMap, FontAxes) \
|
||||||
|
X(winrt::Microsoft::Terminal::Control::IKeyBindings, KeyBindings, nullptr) \
|
||||||
|
X(winrt::hstring, Commandline) \
|
||||||
|
X(winrt::hstring, StartingDirectory) \
|
||||||
|
X(winrt::hstring, StartingTitle) \
|
||||||
|
X(bool, SuppressApplicationTitle) \
|
||||||
|
X(winrt::hstring, EnvironmentVariables) \
|
||||||
|
X(winrt::Microsoft::Terminal::Control::ScrollbarState, ScrollState, winrt::Microsoft::Terminal::Control::ScrollbarState::Visible) \
|
||||||
|
X(winrt::Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale) \
|
||||||
|
X(bool, ForceFullRepaintRendering, false) \
|
||||||
|
X(bool, SoftwareRendering, false) \
|
||||||
|
X(bool, ForceVTInput, false) \
|
||||||
|
X(bool, UseAtlasEngine, false)
|
|
@ -324,9 +324,9 @@ void AtlasEngine::SetCallback(std::function<void()> pfn) noexcept
|
||||||
_api.swapChainChangedCallback = std::move(pfn);
|
_api.swapChainChangedCallback = std::move(pfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtlasEngine::SetDefaultTextBackgroundOpacity(const float opacity) noexcept
|
void AtlasEngine::EnableTransparentBackground(const bool isTransparent) noexcept
|
||||||
{
|
{
|
||||||
const auto mixin = opacity == 1.0f ? 0xff000000 : 0x00000000;
|
const auto mixin = !isTransparent ? 0xff000000 : 0x00000000;
|
||||||
if (_api.backgroundOpaqueMixin != mixin)
|
if (_api.backgroundOpaqueMixin != mixin)
|
||||||
{
|
{
|
||||||
_api.backgroundOpaqueMixin = mixin;
|
_api.backgroundOpaqueMixin = mixin;
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace Microsoft::Console::Render
|
||||||
// DxRenderer - setter
|
// DxRenderer - setter
|
||||||
void SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept override;
|
void SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept override;
|
||||||
void SetCallback(std::function<void()> pfn) noexcept override;
|
void SetCallback(std::function<void()> pfn) noexcept override;
|
||||||
void SetDefaultTextBackgroundOpacity(float opacity) noexcept override;
|
void EnableTransparentBackground(const bool isTransparent) noexcept override;
|
||||||
void SetForceFullRepaintRendering(bool enable) noexcept override;
|
void SetForceFullRepaintRendering(bool enable) noexcept override;
|
||||||
[[nodiscard]] HRESULT SetHwnd(HWND hwnd) noexcept override;
|
[[nodiscard]] HRESULT SetHwnd(HWND hwnd) noexcept override;
|
||||||
void SetPixelShaderPath(std::wstring_view value) noexcept override;
|
void SetPixelShaderPath(std::wstring_view value) noexcept override;
|
||||||
|
|
|
@ -88,7 +88,7 @@ DxEngine::DxEngine() :
|
||||||
_forceFullRepaintRendering{ false },
|
_forceFullRepaintRendering{ false },
|
||||||
_softwareRendering{ false },
|
_softwareRendering{ false },
|
||||||
_antialiasingMode{ D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE },
|
_antialiasingMode{ D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE },
|
||||||
_defaultTextBackgroundOpacity{ 1.0f },
|
_defaultBackgroundIsTransparent{ true },
|
||||||
_hwndTarget{ static_cast<HWND>(INVALID_HANDLE_VALUE) },
|
_hwndTarget{ static_cast<HWND>(INVALID_HANDLE_VALUE) },
|
||||||
_sizeTarget{},
|
_sizeTarget{},
|
||||||
_dpi{ USER_DEFAULT_SCREEN_DPI },
|
_dpi{ USER_DEFAULT_SCREEN_DPI },
|
||||||
|
@ -911,7 +911,7 @@ void DxEngine::_ReleaseDeviceResources() noexcept
|
||||||
// someone has chosen the slower ClearType antialiasing (versus the faster
|
// someone has chosen the slower ClearType antialiasing (versus the faster
|
||||||
// grayscale antialiasing)
|
// grayscale antialiasing)
|
||||||
const bool usingCleartype = _antialiasingMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
const bool usingCleartype = _antialiasingMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
||||||
const bool usingTransparency = _defaultTextBackgroundOpacity != 1.0f;
|
const bool usingTransparency = _defaultBackgroundIsTransparent;
|
||||||
// Another way of naming "bgIsDefault" is "bgHasTransparency"
|
// Another way of naming "bgIsDefault" is "bgHasTransparency"
|
||||||
const auto bgIsDefault = (_backgroundColor.a == _defaultBackgroundColor.a) &&
|
const auto bgIsDefault = (_backgroundColor.a == _defaultBackgroundColor.a) &&
|
||||||
(_backgroundColor.r == _defaultBackgroundColor.r) &&
|
(_backgroundColor.r == _defaultBackgroundColor.r) &&
|
||||||
|
@ -1927,20 +1927,16 @@ CATCH_RETURN()
|
||||||
const bool /*usingSoftFont*/,
|
const bool /*usingSoftFont*/,
|
||||||
const bool isSettingDefaultBrushes) noexcept
|
const bool isSettingDefaultBrushes) noexcept
|
||||||
{
|
{
|
||||||
// GH#5098: If we're rendering with cleartype text, we need to always render
|
|
||||||
// onto an opaque background. If our background's opacity is 1.0f, that's
|
|
||||||
// great, we can actually use cleartype in that case. In that scenario
|
|
||||||
// (cleartype && opacity == 1.0), we'll force the opacity bits of the
|
|
||||||
// COLORREF to 0xff so we draw as cleartype. In any other case, leave the
|
|
||||||
// opacity bits unchanged. PaintBufferLine will later do some logic to
|
|
||||||
// determine if we should paint the text as grayscale or not.
|
|
||||||
const bool usingCleartype = _antialiasingMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
||||||
const bool usingTransparency = _defaultTextBackgroundOpacity != 1.0f;
|
|
||||||
const bool forceOpaqueBG = usingCleartype && !usingTransparency;
|
|
||||||
|
|
||||||
const auto [colorForeground, colorBackground] = pData->GetAttributeColors(textAttributes);
|
const auto [colorForeground, colorBackground] = pData->GetAttributeColors(textAttributes);
|
||||||
|
|
||||||
|
const bool usingCleartype = _antialiasingMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
||||||
|
const bool usingTransparency = _defaultBackgroundIsTransparent;
|
||||||
|
const bool forceOpaqueBG = usingCleartype && !usingTransparency;
|
||||||
|
|
||||||
_foregroundColor = _ColorFFromColorRef(OPACITY_OPAQUE | colorForeground);
|
_foregroundColor = _ColorFFromColorRef(OPACITY_OPAQUE | colorForeground);
|
||||||
|
// October 2021: small changes were made to the way BG color interacts with
|
||||||
|
// grayscale AA, esp. with regards to acrylic and GH#5098. See comment in
|
||||||
|
// _ShouldForceGrayscaleAA for more details.
|
||||||
_backgroundColor = _ColorFFromColorRef((forceOpaqueBG ? OPACITY_OPAQUE : 0) | colorBackground);
|
_backgroundColor = _ColorFFromColorRef((forceOpaqueBG ? OPACITY_OPAQUE : 0) | colorBackground);
|
||||||
|
|
||||||
_d2dBrushForeground->SetColor(_foregroundColor);
|
_d2dBrushForeground->SetColor(_foregroundColor);
|
||||||
|
@ -2237,14 +2233,19 @@ CATCH_LOG()
|
||||||
// rendering onto a transparent surface (like acrylic), then cleartype won't
|
// rendering onto a transparent surface (like acrylic), then cleartype won't
|
||||||
// work correctly, and will actually just additively blend with the
|
// work correctly, and will actually just additively blend with the
|
||||||
// background. This is here to support GH#5098.
|
// background. This is here to support GH#5098.
|
||||||
|
// - We'll use this, along with whether cleartype was requested, to manually set
|
||||||
|
// the alpha channel of the background brush to 1.0. We need to do that to
|
||||||
|
// make cleartype work without blending. However, we don't want to do that too
|
||||||
|
// often - if we do that on top of a transparent BG, then the entire swap
|
||||||
|
// chain will be fully opaque.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - opacity: the new opacity of our background, on [0.0f, 1.0f]
|
// - isTransparent: true if our BG is transparent (acrylic, or anything that's not fully opaque)
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <none>
|
||||||
void DxEngine::SetDefaultTextBackgroundOpacity(const float opacity) noexcept
|
void DxEngine::EnableTransparentBackground(const bool isTransparent) noexcept
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_defaultTextBackgroundOpacity = opacity;
|
_defaultBackgroundIsTransparent = isTransparent;
|
||||||
|
|
||||||
// Make sure we redraw all the cells, to update whether they're actually
|
// Make sure we redraw all the cells, to update whether they're actually
|
||||||
// drawn with cleartype or not.
|
// drawn with cleartype or not.
|
||||||
|
|
|
@ -128,7 +128,7 @@ namespace Microsoft::Console::Render
|
||||||
|
|
||||||
void SetSelectionBackground(const COLORREF color, const float alpha = 0.5f) noexcept override;
|
void SetSelectionBackground(const COLORREF color, const float alpha = 0.5f) noexcept override;
|
||||||
void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept override;
|
void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept override;
|
||||||
void SetDefaultTextBackgroundOpacity(const float opacity) noexcept override;
|
void EnableTransparentBackground(const bool isTransparent) noexcept override;
|
||||||
void SetIntenseIsBold(const bool opacity) noexcept override;
|
void SetIntenseIsBold(const bool opacity) noexcept override;
|
||||||
|
|
||||||
void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept override;
|
void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept override;
|
||||||
|
@ -257,7 +257,7 @@ namespace Microsoft::Console::Render
|
||||||
|
|
||||||
D2D1_TEXT_ANTIALIAS_MODE _antialiasingMode;
|
D2D1_TEXT_ANTIALIAS_MODE _antialiasingMode;
|
||||||
|
|
||||||
float _defaultTextBackgroundOpacity;
|
bool _defaultBackgroundIsTransparent;
|
||||||
bool _intenseIsBold;
|
bool _intenseIsBold;
|
||||||
|
|
||||||
// DirectX constant buffers need to be a multiple of 16; align to pad the size.
|
// DirectX constant buffers need to be a multiple of 16; align to pad the size.
|
||||||
|
|
|
@ -104,7 +104,7 @@ namespace Microsoft::Console::Render
|
||||||
// DxRenderer - setter
|
// DxRenderer - setter
|
||||||
virtual void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept {}
|
virtual void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept {}
|
||||||
virtual void SetCallback(std::function<void()> pfn) noexcept {}
|
virtual void SetCallback(std::function<void()> pfn) noexcept {}
|
||||||
virtual void SetDefaultTextBackgroundOpacity(const float opacity) noexcept {}
|
virtual void EnableTransparentBackground(const bool isTransparent) noexcept {}
|
||||||
virtual void SetForceFullRepaintRendering(bool enable) noexcept {}
|
virtual void SetForceFullRepaintRendering(bool enable) noexcept {}
|
||||||
virtual [[nodiscard]] HRESULT SetHwnd(const HWND hwnd) noexcept { return E_NOTIMPL; }
|
virtual [[nodiscard]] HRESULT SetHwnd(const HWND hwnd) noexcept { return E_NOTIMPL; }
|
||||||
virtual void SetPixelShaderPath(std::wstring_view value) noexcept {}
|
virtual void SetPixelShaderPath(std::wstring_view value) noexcept {}
|
||||||
|
|
Loading…
Reference in a new issue